dry-rb / dry-inflector

Inflector for Ruby
https://dry-rb.org/gems/dry-inflector
MIT License
95 stars 15 forks source link

Inflector future #9

Closed Ptico closed 6 years ago

Ptico commented 6 years ago

Hi, I have some thoughts on future changes which I want do discuss (and possibly implement).

1. Inflections ruleset:

As long as we move to normal instantiated object, we may want to create predefined rulesets with different inflection rules. I suggest to change API a bit and introduce Dry::Inflector::Ruleset , suggested usage:

RULESET_ONE = Dry::Inflector::Ruleset.new do
  plural "virus", "viruses"
  singular "thieves", "thief"
end

RULESET_TWO = Dry::Inflector::Ruleset.net do
  load_defaults!
  uncountable "dry-inflector"
end

inflector = Dry::Inflector.new(condition ? RULESET_ONE : RULESET_TWO)

If we just want to use defaults, we can use Dry::Inflector::Ruleset::DEFAULT. The only question is should we include them if nothing passed to constructor?

inflector = Dry::Inflector.new # <= what should we use?

Also, I think we need to keep possibility to just pass a block to constructor and have #inflections method:

inflector = Dry::Inflector.new do
  plural "virus", "viruses"
end

inflector.inflections do
  singular "thieves", "thief"
end

2. Module

In some cases, users may want to just include Dry::Inflector as module (helper) to their own objects. I don't know if this is a good idea, but for the objects with heavy inflector usage or something like views it may be really handy.

If we will decide to implement a module, I also want to discuss possibility of module builder, so we can pick only helpers we need:

class MyClass
  include Dry::Inflector.module(:pluralize, :singularize)
end

Main question here, is how we may configure rulesets? Should we pass ruleset to .module? Or add the #inflection method to instance? What to do when method depends on ruleset and what if not (dasherize for example)?

Note that main interface in this case still Dry::Inflector.new we just add another one API.

So, let's discuss.

abinoam commented 6 years ago

Hi @Ptico

Also, I think we need to keep possibility to just pass a block to constructor and have #inflections method

I think this goes against the immutability mindset of dry-rb. Confirm @solnic and @jodosha? I think it's better to just fire up a new Dry::Inflector instance.

But, this will let us with one problem. If we a have an "already" customized inflector instance that came from outside our code, and we just want to add some more custom rules? This was the problem solved by #inflections with a block. Perhaps we should have a kind of copy and customize feature to fill in the gap left by inflections method. What do you think?

abinoam commented 6 years ago
  1. Inflections ruleset:

I'll have to think more about this. I think this would be the place for internationalization. (although I don't think internationalization is a priority here, as most projects uses english words for tables, code, models and so on).

jodosha commented 6 years ago

@Ptico Hi and thanks for starting this discussion.

1. Inflections ruleset:

I think we should put in average developer's shoes. What's the most common operation that they want to do? Probably instantiate the inflector and pluralize a string.

inflector = Dry::Inflector.new
inflector.pluralize("book")

How we can keep this simplicity and make it compatible with advanced configuration cases? IMO, we can change #initialize method like this:

    def initialize(inflections: Inflections.defaults, &blk)
      @inflections = Inflections.build(inflections, &blk)
    end

In this way we can still satisfy the existing use cases:

# 1
Dry::Inflector.new

# 2
Dry::Inflector.new do |inflections|
  inflections.plural "virus", "viruses"
end

But it can second new cases like:

Dry::Inflector.new(inflections: nil) do |inflections|
  inflections.plural "libro", "libri" # Italian words for "book" and "books"
end

Or

italian = Dry::Inflector::Inflections.new do |inflections|
  inflections.plural "libro", "libri"
end

inflector = Dry::Inflector.new(inflections: italian)
inflector.pluralize("libro")

Would this help with I18n?


I vote against an #inflections method that mutates the object after its initialization. πŸ‘Ž It's again the problem that mutations in the inflection rules may alter the result of a pluralization over the time.

2. Module

I'm not sure I've got the point of this proposal. πŸ˜… Can you please explain what's the purpose of it. Code examples would help a lot. Thanks!

Ptico commented 6 years ago

@abinoam ok, let's drop #inflections :)

@jodosha

Can you please explain what's the purpose of it. Code examples would help a lot. Thanks!

This is mostly for helpers and objects with heavy inflector usage:

class PostsView
  include Dry::Inflector.module
end

a(href: "/users/#{underscore(name)}")

From the other side, it requires a lot of effort for such rare use case.

abinoam commented 6 years ago

I trying to remember a gem that had this same type of "module builder" strategy. I know I have already used something like this. I think it's cool, useable and easily feasable. πŸ‘

jodosha commented 6 years ago

@abinoam It's dry-types πŸ˜‰

I'm not sure if this is something to support. The receiver class will mixin too many responsibilities: the primary concern (eg the view) and the inflection concern. Using an object (like the actual design) ease composition over inheritance. WDYT?

solnic commented 6 years ago

I don't think it's a good idea to have Dry::Inflector.module, we should make it clear that dry-inflector provides an object, that you can use as an explicit dependency injected into a constructor. People can use whatever technique they prefer to provide an inflector to their objects. For example in our dry web apps, it'd be one of the "services" that we have, and it'd be automatically provided via auto-injection.

solnic commented 6 years ago

Oh one more thing, we actually have established "Issue Guidelines", and we're not using issues for discussions.

abinoam commented 6 years ago

@abinoam It's dry-types πŸ˜‰

:joy: Yes!!! I was needing some sleep, surely. :joy:

abinoam commented 6 years ago

Oh one more thing, we actually have established "Issue Guidelines", and we're not using issues for discussions.

Sorry @solnic, I was not aware of the guideline. No problem at all. Let's move this discussion to discourse. Feel free to enforce the dry-rb community standards. πŸ‘

solnic commented 6 years ago

@abinoam no worries, I forgot to mention that before. I'll add CONTRIBUTING.md to this project too.

abinoam commented 6 years ago

@solnic , should I use category "Ideas" for this kind of topic? Is there a specific tag/category for dry-inflector already?

abinoam commented 6 years ago

Moved the inflector ruleset discussion to https://discourse.dry-rb.org/t/dry-inflector-future-api/398

abinoam commented 6 years ago

Move the inflector as module discussion to https://discourse.dry-rb.org/t/dry-inflector-as-module/399

abinoam commented 6 years ago

By the way, I'm not being able to ping @Ptico nor @jodosha on discourse forum.

jodosha commented 6 years ago

@abinoam I just signed up on the forum. Thanks.