carlosantoniodasilva/i18n_alchemy

Standardize the API

Closed this issue · 5 comments

All attributes parser are modules and the association parser is an class.

To create custom parsers is more easy to do this with a class instead a module, see:

module CompetenceParser
  include I18n::Alchemy::DateParser
  extend self

  def localize(value)
    if value
      I18n.localize value, :format => :competence
    else
      value
    end
  end

  protected

  def i18n_format
    I18n.t(:competence, :scope => [:date, :formats])
  end
end

With a class we can do this:

class CompetenceParser < I18n::Alchemy::DateParser
  def localize(value)
    if value
      I18n.localize value, :format => :competence
    else
      value
    end
  end

  protected

  def i18n_format
    I18n.t(:competence, :scope => [:date, :formats])
  end
end

Or we can do more:

class CompetenceParser < I18n::Alchemy::DateParser
  def localize(value)
    if value
      I18n.localize value, :format => :competence
    else
      super
    end
  end

  protected

  def i18n_format
    I18n.t(:competence, :scope => [:date, :formats]) || super
  end
end

And with a class, we can raise exceptions without some methods like localize or parser.

raise "You must implement localize" unless parser.respond_to?(:localize)

What do you think?

I agree that it seems easier to implement a custom parser just by inheriting from a class rather than including a module, but at the end, there's no real gain. You don't need to use extend self if you don't want, for instance, or you don't even need to include/inherit from I18n::Alchemy.

super and raise can be implemented as is, by including a module you can call super, so for this case I think there's no real advantage on one or another approach.

A bit of history: parsers are implemented as modules because they don't actually need to save any state, they're just a bunch of related methods grouped by a module. So initially, there was no need to do DateParser.new.parse if you didn't need to... DateParser.parse was enough. On the other hand, AssociationParser was added later specifically to parse a hash of attributes from associations (if the association was localized), before assigning these attributes. There's no concept of localize in AssociationParser. It'd even be better to call it Association only I think.

That said, I feel a bit unsure to change the parsers from modules to classes. Do you have anything else in mind to do with a class instead?

Also, if we go with a class model, do you think we should instantiate them only once for that particular localized object, on every parse/localize call, or only once for the entire application (singleton)?

Thanks mate! :)

Singleton is a good approach!

I thinking in a class because I not "saw" an standard API to build my own custom parsers, as I said, I thinking in an standard API to that anyone can easily build own API :)

The API should be an object that responds to both localize and parse. Whether it's a class or a module or something else, should't really matter :). The case is when someone is using a default parser and extending it.

But yeah, I agree we can have something that shows the common approach to do that, thanks!

@carlosantoniodasilva can be closed due to a lack of activity.

README already have the instructions for custom parsers.