Skip to content
Extraits de code Groupes Projets
Valider bfb4ac4b rédigé par Daniel Grippi's avatar Daniel Grippi
Parcourir les fichiers

Merge pull request #2296 from Pistos/issue-2264-fix-tag-parsing

Issue 2264 fix tag parsing
parents 066f8d12 b3853f48
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
module Diaspora module Diaspora
module Taggable module Taggable
VALID_TAG_BODY = /[^_,\s#*\[\]()\@\/"'\.%]+\b/
def self.included(model) def self.included(model)
model.class_eval do model.class_eval do
cattr_accessor :field_with_tags cattr_accessor :field_with_tags
...@@ -27,10 +25,11 @@ module Diaspora ...@@ -27,10 +25,11 @@ module Diaspora
end end
def tag_strings def tag_strings
regex = /(?:^|\s)#(#{VALID_TAG_BODY})/ regex = /(?:^|\s)#([\w-]+|<3)/
matches = self.send(self.class.field_with_tags).scan(regex).map do |match| matches = self.
match.last send( self.class.field_with_tags ).
end scan(regex).
map { |match| match[0] }
unique_matches = matches.inject(Hash.new) do |h,element| unique_matches = matches.inject(Hash.new) do |h,element|
h[element.downcase] = element unless h[element.downcase] h[element.downcase] = element unless h[element.downcase]
h h
...@@ -39,13 +38,20 @@ module Diaspora ...@@ -39,13 +38,20 @@ module Diaspora
end end
def self.format_tags(text, opts={}) def self.format_tags(text, opts={})
return text if opts[:plain_text] return text if opts[:plain_text]
text = ERB::Util.h(text) unless opts[:no_escape] text = ERB::Util.h(text) unless opts[:no_escape]
regex = /(^|\s|>)#(#{VALID_TAG_BODY})/ regex = /(^|\s|>)#([\w-]+|&lt;3)/
form_message = text.to_str.gsub(regex) do |matched_string|
"#{$~[1]}<a href=\"/tags/#{$~[2]}\" class=\"tag\">##{$~[2]}</a>" text.to_str.gsub(regex) { |matched_string|
end pre, url_bit, clickable = $1, $2, "##{$2}"
form_message.html_safe if $2 == '&lt;3'
# Special case for love, because the world needs more love.
url_bit = '<3'
end
%{#{pre}<a href="/tags/#{url_bit}" class="tag">#{clickable}</a>}
}.html_safe
end end
end end
end end
...@@ -12,6 +12,10 @@ describe Diaspora::Taggable do ...@@ -12,6 +12,10 @@ describe Diaspora::Taggable do
def controller def controller
end end
def tag_link(s)
link_to "##{s}", "/tags/#{s}", :class => 'tag'
end
describe '.format_tags' do describe '.format_tags' do
before do before do
@str = '#what #hey #vöglein' @str = '#what #hey #vöglein'
...@@ -19,14 +23,63 @@ describe Diaspora::Taggable do ...@@ -19,14 +23,63 @@ describe Diaspora::Taggable do
@object.build_tags @object.build_tags
@object.save! @object.save!
end end
it 'links the tag to /p' do it 'links the tag to /p' do
link = link_to('#vöglein', '/tags/vöglein', :class => 'tag') Diaspora::Taggable.format_tags(@str).should include( tag_link('vöglein') )
Diaspora::Taggable.format_tags(@str).should include(link)
end end
it 'responds to plain_text' do it 'responds to plain_text' do
Diaspora::Taggable.format_tags(@str, :plain_text => true).should == @str Diaspora::Taggable.format_tags(@str, :plain_text => true).should == @str
end end
it "doesn't mangle text when tags are involved" do
expected = {
nil => '',
'' => '',
'abc' => 'abc',
'a #b c' => "a #{tag_link('b')} c",
'#' => '#',
'##' => '##',
'###' => '###',
'#a' => tag_link('a'),
'#foobar' => tag_link('foobar'),
'#foocar<br>' => "#{tag_link('foocar')}&lt;br&gt;",
'#fooo@oo' => "#{tag_link('fooo')}@oo",
'#num3ric hash tags' => "#{tag_link('num3ric')} hash tags",
'#12345 tag' => "#{tag_link('12345')} tag",
'#12cde tag' => "#{tag_link('12cde')} tag",
'#abc45 tag' => "#{tag_link('abc45')} tag",
'#<3' => %{<a href="/tags/<3" class="tag">#&lt;3</a>},
'i #<3' => %{i <a href="/tags/<3" class="tag">#&lt;3</a>},
'i #<3 you' => %{i <a href="/tags/<3" class="tag">#&lt;3</a> you},
'#<4' => '#&lt;4',
'test#foo test' => 'test#foo test',
'test.#joo bar' => 'test.#joo bar',
'test #foodar test' => "test #{tag_link('foodar')} test",
'test #foofar<br> test' => "test #{tag_link('foofar')}&lt;br&gt; test",
'test #gooo@oo test' => "test #{tag_link('gooo')}@oo test",
'test #foo-test test' => "test #{tag_link('foo-test')} test",
'test #hoo' => "test #{tag_link('hoo')}",
'test #two_word tags' => "test #{tag_link('two_word')} tags",
'test #three_word_tags' => "test #{tag_link('three_word_tags')}",
'#terminal_underscore_' => tag_link('terminal_underscore_'),
'#terminalunderscore_' => tag_link('terminalunderscore_'),
'#_initialunderscore' => tag_link('_initialunderscore'),
'#_initial_underscore' => tag_link('_initial_underscore'),
'#terminalhyphen-' => tag_link('terminalhyphen-'),
'#terminal-hyphen-' => tag_link('terminal-hyphen-'),
'#terminalhyphen- tag' => "#{tag_link('terminalhyphen-')} tag",
'#-initialhyphen' => tag_link('-initialhyphen'),
'#-initialhyphen tag' => "#{tag_link('-initialhyphen')} tag",
'#-initial-hyphen' => tag_link('-initial-hyphen'),
}
expected.each do |input,output|
Diaspora::Taggable.format_tags(input).should == output
end
end
end end
describe '#build_tags' do describe '#build_tags' do
it 'builds the tags' do it 'builds the tags' do
@object.send(@object.class.field_with_tags_setter, '#what') @object.send(@object.class.field_with_tags_setter, '#what')
...@@ -37,14 +90,60 @@ describe Diaspora::Taggable do ...@@ -37,14 +90,60 @@ describe Diaspora::Taggable do
}.should change{@object.tags.count}.by(1) }.should change{@object.tags.count}.by(1)
end end
end end
describe '#tag_strings' do describe '#tag_strings' do
it 'returns a string for every #thing' do it 'returns a string for every #thing' do
str = '#what #hey #that"smybike. #@hey ##boo # #THATWASMYBIKE #vöglein #hey#there #135440we #abc/23 ### #h!gh #ok? #see: #re:publica' str = '#what #hey #that"smybike. #@hey ##boo # #THATWASMYBIKE #vöglein #hey#there #135440we #abc/23 ### #h!gh #ok? #see: #re:publica'
arr = ['what', 'hey', 'that', 'THATWASMYBIKE', 'vöglein', '135440we', 'abc', 'h!gh', 'ok', 'see', 're:publica'] arr = ['what', 'hey', 'that', 'THATWASMYBIKE', 'vöglein', '135440we', 'abc', 'h', 'ok', 'see', 're']
@object.send(@object.class.field_with_tags_setter, str) @object.send(@object.class.field_with_tags_setter, str)
@object.tag_strings.should =~ arr @object.tag_strings.should =~ arr
end end
it 'extracts tags despite surrounding text' do
expected = {
'' => nil,
'#' => nil,
'##' => nil,
'###' => nil,
'#a' => 'a',
'#foobar' => 'foobar',
'#foocar<br>' => 'foocar',
'#fooo@oo' => 'fooo',
'#num3ric hash tags' => 'num3ric',
'#12345 tag' => '12345',
'#12cde tag' => '12cde',
'#abc45 tag' => 'abc45',
'#<3' => '<3',
'#<4' => nil,
'test#foo test' => nil,
'test.#joo bar' => nil,
'test #foodar test' => 'foodar',
'test #foofar<br> test' => 'foofar',
'test #gooo@oo test' => 'gooo',
'test #<3 test' => '<3',
'test #foo-test test' => 'foo-test',
'test #hoo' => 'hoo',
'test #two_word tags' => 'two_word',
'test #three_word_tags' => 'three_word_tags',
'#terminal_underscore_' => 'terminal_underscore_',
'#terminalunderscore_' => 'terminalunderscore_',
'#_initialunderscore' => '_initialunderscore',
'#_initial_underscore' => '_initial_underscore',
'#terminalhyphen-' => 'terminalhyphen-',
'#terminal-hyphen-' => 'terminal-hyphen-',
'#terminalhyphen- tag' => 'terminalhyphen-',
'#-initialhyphen' => '-initialhyphen',
'#-initialhyphen tag' => '-initialhyphen',
'#-initial-hyphen' => '-initial-hyphen',
}
expected.each do |text,hashtag|
@object.send @object.class.field_with_tags_setter, text
@object.tag_strings.should == [hashtag].compact
end
end
it 'returns no duplicates' do it 'returns no duplicates' do
str = '#what #what #what #whaaaaaaaaaat' str = '#what #what #what #whaaaaaaaaaat'
arr = ['what','whaaaaaaaaaat'] arr = ['what','whaaaaaaaaaat']
...@@ -52,6 +151,7 @@ describe Diaspora::Taggable do ...@@ -52,6 +151,7 @@ describe Diaspora::Taggable do
@object.send(@object.class.field_with_tags_setter, str) @object.send(@object.class.field_with_tags_setter, str)
@object.tag_strings.should =~ arr @object.tag_strings.should =~ arr
end end
it 'is case insensitive' do it 'is case insensitive' do
str = '#what #wHaT #WHAT' str = '#what #wHaT #WHAT'
arr = ['what'] arr = ['what']
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter