pat / gutentag

A good, simple, solid tagging extension for ActiveRecord.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

obj.tag_names not supporting for String

RajRoR opened this issue · comments

In version, 0.5.0, we had support for setting tag_names with String, i.e. ar_obj.tag_names = 'test1'.

However, in later version, tag_names= is expecting array and throwing following exception for strings:

TypeError Exception: no implicit conversion of String into Array

Hi Raj

What behaviour are you expecting when a string is passed through - that the entire string is a single tag? The string should be split by commas and resulting values treated as strings? Or something else?

Second one i.e. "test1, test2" should be stored as 2 tags, "test1" and
"test2".

Thanks
Raj

Normal fingers, tiny keyboard - sent via Gmail Mobile
On 18-Apr-2015 1:57 PM, "Pat Allan" notifications@github.com wrote:

Hi Raj

What behaviour are you expecting when a string is passed through - that
the entire string is a single tag? The string should be split by commas and
resulting values treated as strings? Or something else?


Reply to this email directly or view it on GitHub
#15 (comment).

I just checked out the v0.5.0 tag locally, ran the following test, and it fails with undefined methodcollect' for "melbourne, tags":String`:

it 'allows parsing of strings' do
  article.tag_names = 'melbourne, tags'
  article.save!

  expect(article.tags.collect(&:name)).to eq(['melbourne', 'tags'])
end

So, I'm not sure if the behaviour you're describing ever existed?

Thanks @pat for your support, however, it was working till this commit: https://github.com/pat/gutentag/tree/edaecb20d3aa61f81550c368f6cf366e65af5405

Can you try this please?

Which version of Rails are you using? Because on that commit, and the one before it, my test still fails.

I am using Rails-4.1.4.

I am minding this: edaecb2#diff-039fccfbdf033e0da76e4eba64491c76R35 where string is getting splatted by comma.

Ah, I see what you mean...

Though that behaviour only existed for that single commit! The very next commit is a refactoring of that logic, and it removes the split call.

So it now becomes a question of whether I want to return to supporting that behaviour (and really, consider it as an official feature, because it certainly wasn't previously). I'm not too thrilled about allowing both strings and arrays as a valid method argument, especially since the method consistently returns an array. Granted, I can see the usefulness, but I also like keeping Gutentag quite simple and focused. It's 1am here, so I'm going to sleep on it, and see what I think tomorrow.

Good night Pat, hoping for best :)

I'll wait for your further response on this.

Thanks
Raj

Normal fingers, tiny keyboard - sent via Gmail Mobile
On 18-Apr-2015 8:30 PM, "Pat Allan" notifications@github.com wrote:

Ah, I see what you mean...

Though that behaviour only existed for that single commit! The very next
commit is a refactoring of that logic, and it removes the split call.

So it now becomes a question of whether I want to return to supporting
that behaviour (and really, consider it as an official feature, because it
certainly wasn't previously). I'm not too thrilled about allowing both
strings and arrays as a valid method argument, especially since the method
consistently returns an array. Granted, I can see the usefulness, but I
also like keeping Gutentag quite simple and focused. It's 1am here, so I'm
going to sleep on it, and see what I think tomorrow.


Reply to this email directly or view it on GitHub
#15 (comment).

I've decided I'm not going to support this, because a proper implementation would involve too much code that I really don't want to maintain, even though I've figured it out.

Firstly, it's worth noting that my approach would be to have separate methods that get and accept a string representation of the tags, comma-separated. A simple implementation would be the following:

def tag_string
  tag_names.join ', '
end

def tag_string=(string)
  self.tag_names = string.split /,\s?/
end

However, that does not allow for tags with commas in their names. Let's say that you'd wrap any tag name in double-quotes if there's a comma within it... then a reasonably reliable implementation would be looking like this:

def tag_string
  tag_names.collect { |name| name[/,/] ? "\"#{name}\"" : name }.join(', ')
end

def tag_string=(string)
  words = []
  field = ''
  string.scan(/\G\s*(?>([^,\s?\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|\\.)*)"|(\\.?)|([^,]))(,\s?|\z)?/m) do
    |word, sq, dq, esc, garbage, sep|
    raise ArgumentError, "Unmatched double quote: #{string.inspect}" if garbage
    field << (word || sq || (dq || esc).gsub(/\\(.)/, '\\1'))
    if sep
      words << field
      field = ''
    end
  end
  self.tag_names = words
end

The regular expression logic there is adapted from Ruby's shellwords code (in the standard library). Copy-and-pasting that code and changing whitespace markers to commas in the pattern isn't too hard, but I don't fully grok it. I especially don't like the abbreviated arguments (sq, dq, esc, sep). And this implementation raises questions around what should happen if tag names have double-quotes within them - what's the behaviour in those situations? This code is what I don't want to maintain.

If it wasn't so complex, I'd probably put this in... indeed, I've got the code pretty much written (obviously, given I'm sharing it here). But I figure you can take either version and use it as necessary within your models if you want to.

Makes sense @pat and thanks for detailed explaination