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