Если вы разрабатываете приложение на Ruby on Rails вроде блога, возможно вам понадобится генерировать URLы используя заголовки статей. Это хорошая практика, потому что поисковики обожают ключевые слова в URLах, да и выглядят они более человеко-читабельными. Просто сравните: http://example.com/posts/10 и http://example.com/posts/generating-permalinks-from-string (угу, длинновато, но зато наглядно). А любом случае, это короткая заметка о преобразовании заголовка в постоянную ссылку.
Основная вещь, которую я обожаю в Ruby — это возможность расширять классы своими собственными методами. Я могу просто добавить метод to_permalink любой строке, и затем где угодно использовать что-то вроде @post.title.to_permalink. Это офигенно!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | class String def to_permalink result = strip_tags # Preserve escaped octets. result.gsub!(/-+/, '-') result.gsub!(/%([a-f0-9]{2})/i, '--\1--') # Remove percent signs that are not part of an octet. result.gsub!('%', '-') # Restore octets. result.gsub!(/--([a-f0-9]{2})--/i, '%\1') result.gsub!(/&.+?;/, '-') # kill entities result.gsub!(/[^%a-z0-9_-]+/i, '-') result.gsub!(/-+/, '-') result.gsub!(/(^-+|-+$)/, '') return result.downcase end private def strip_tags return clone if blank? if index('<') text = '' tokenizer = HTML::Tokenizer.new(self) while token = tokenizer.next node = HTML::Node.parse(nil, 0, 0, token, false) # result is only the content of any Text nodes text << node.to_s if node.class == HTML::Text end # strip any comments, and if they have a newline at the end (ie. line with # only a comment) strip that too text.gsub(/<!--(.*?)-->[\n]?/m, '') else clone # already plain text end end end |
Как это работает? Первое, что вы скорее всего заметили,– это приватный метод strip_tags. Да, я знаю об ActionView::Helpers::TextHelper::strip_tags, и это почти 100% копия версии из Rails (отличие только в том, что мой код всегда возвращает копию исходной строки). Я просто не хочу зависеть от рельсовых библиотек.
Далее мой метод заменяет все специальные символы на дефисы (остаются только октеты вроде %A0), и обрезает дефисы в начале и в конце строки. Ну и перед выходом строка будет приведена к нижнему регистру.
Естественно, в вашем приложении вы должны проверить коллизии (несколько статей с одинаковыми заголовками должны иметь уникальные постоянные ссылки, например вы можете добавлять числа начиная с 1: hello, hello-1, hello-2 и т.д.). У меня нет желания описывать все сложности, с которыми вы можете столкнуться, это ведь короткая заметка, вы же помните?
Удовольствия ради, вот тесты RSpec для этого метода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | describe 'String.to_permalink from extensions.rb' do it 'should replace all punctuation marks and spaces with dashes' do "!.@#$\%^&*()Test case\n\t".to_permalink.should == 'test-case' end it 'should preserve _ symbol' do "Test_case".to_permalink.should == 'test_case' end it 'should preserve escaped octets and remove redundant %' do 'Test%%20case'.to_permalink.should == 'test-%20case' end it 'should strip HTML tags' do '<a href="http://example.com">Test</a> <b>case</b>'.to_permalink.should == 'test-case' end it 'should strip HTML entities and insert dashes' do 'Test case'.to_permalink.should == 'test-case' end it 'should trim beginning and ending dashes' do '-. Test case .-'.to_permalink.should == 'test-case' end it 'should not use ---aa--- as octet' do 'b---aa---b'.to_permalink.should == 'b-aa-b' end it 'should replace % with -' do 'Hello%world'.to_permalink.should == 'hello-world' end it 'should not modify original string' do s = 'Hello, <b>world</b>%20' s.to_permalink.should == 'hello-world%20' s.should == 'Hello, <b>world</b>%20' s = 'Hello' s.to_permalink.should == 'hello' s.should == 'Hello' end end |
Прикольно, правда?

Да. ))
Интересно сколько займет ресурсов и как будет выглядеть реализация на php в свете недавнего обсуждения на харахабарачтототам
Да ровно столько же! Все эти войны Something vs. Something another — чистой воды треп людей, которым нечем заняться. При грамотном подходе код в любом языке будет лаконичным и эффективным. Вопрос в компактности и читабельности — это да, целиком ложится на совесть языка.
Вон в комментах к статье о подзапросах я приводил пример кода пхп. Да, задача не повседневная, но классическая, когда надо обработать выборку. И ну никак всего этого уродства не обойти. Можно размазать по коду, это да. Или вынести в отдельный файл и никому не показывать. Но оно останется. Потому что ПХП — это набор знаков препинания, разделенных словами.
Аналога этому в не обьектном языке не напишешь:
2
3
4
5
def to_permalink
end
end
'string'.to_permalink
Только вроде такого
2
3
}
to_permalink($post->title);
Ну почему же. В C# 3.0 можно будет писать extension методы:
2
3
4
5
6
7
8
{
public static String ToPermalink(this String s)
{
}
}
'Something'.ToPermalink();
Это не аналогия открытости классов руби, а просто синтаксический сахар. Но результаты в общем-то неразличимы невооруженным взглядом :-)
а почему просто не переопределить to_param модели?