Giter VIP home page Giter VIP logo

Comments (5)

xymbol avatar xymbol commented on September 27, 2024

@tute, Ambry keeps fields as class attributes which, within Ruby's object model, are not inherited by descendant classes. Of course, this is a well know topic and yes, it can be done.

Still, I think that, for Ambry, inheriting fields wouldn't solve a problem but create a new one. For example, how would you handle a case where you want to inherit behavior but not all attributes? You would need to either remove or reset field attributes until the set matches your need.

Taller class hierarchies are not very modern Ruby-ish in style and less flexible overall. That's why Ambry, and most recent libraries, favor module inclusion/extension over class inheritance.

from ambry.

xymbol avatar xymbol commented on September 27, 2024

@tute, this is the way I'd go for your example:

require 'ambry'
require 'ambry/active_model'

module Badge
  module Basic
    def self.included(klass)
      klass.instance_eval do
        extend Ambry::Model
        extend Ambry::ActiveModel
        field :id, :name, :level, :image, :description
      end
    end
  end
end

class BuyerBadge
  include Badge::Basic
end

class SellerBadge
  include Badge::Basic
  field :featured
end

BuyerBadge.attribute_names # => [:id, :name, :level, :image, :description]
SellerBadge.attribute_names # => [:id, :name, :level, :image, :description, :featured]

Same features without inheritance.

from ambry.

tute avatar tute commented on September 27, 2024

Hi @xymbol. Subclasses not inheriting attributes feel weird to me because it doesn't respect the "is a" relationship. For this example, badges or any of it's subclasses should act semantically as badges, following the substitutability principle.

The reason for subclassing should be that the hierarchy in software design models a hierarchy in the real world, so subclassing for inheriting behavior feels weird to me. If I needed so I'd use module inclusion, as your code example works.

I still vote for Ambry allowing traditional subclassing/subtyping mechanism, though I understand why Ruby community tends to use module inclusion in favor of subclassing.

Thanks for your comments!

from ambry.

xymbol avatar xymbol commented on September 27, 2024

@tute With the risk of starting a completely off-topic debate, the short reply would be that subclassing, especially when dealing with real world models, is usually abused. Yes, we all accept that a scooter and a vessel are subclasses of some sort of vehicle class but, the truth is, they share orders of magnitude less than what they don't.

So, back to your badge example, I would try to think more about what badges are and do instead of internal details, such as persistence, validation, etc. In that respect, Ambry (or whatever ORM) is more like materials or tools to produce your badges, not the badges themselves. They shouldn't be that important.

As an example, let's add an AgentBadge which gets MongoDB persistence via Mongoid.

require 'ambry'
require 'ambry/active_model'
require 'mongoid'

class Badge
  module Ambry
    def self.included(klass)
      klass.instance_eval do
        extend ::Ambry::Model
        extend ::Ambry::ActiveModel
        field :id, :name, :level, :image, :description
      end
    end
  end

  module Mongoid
    def self.included(klass)
      klass.instance_eval do
        include ::Mongoid::Document
        field :name
        field :level, type: Integer
        field :image
        field :description
      end
    end
  end

  def gold?
    level == 3
  end

  def platinum?
    level == 4
  end

  def executive_platinum?
    level == 5
  end

  def premium?
    gold? || platinum? || executive_platinum?
  end
end

class BuyerBadge < Badge
  include Badge::Ambry
end

class SellerBadge < Badge
  include Badge::Ambry
  field :featured
end

class AgentBadge < Badge
  include Badge::Mongoid
  field :commission
end

BuyerBadge.attribute_names # => [:id, :name, :level, :image, :description]
SellerBadge.attribute_names # => [:id, :name, :level, :image, :description, :featured]
AgentBadge.attribute_names # => ["_type", "_id", "name", "level", "image", "description", "commission"]

Now all badges inherit methods from a parent class, whereas persistence is added on a per-class basis.

The difference may seem subtle but the added flexibility is not. Some libraries like ActiveRecord have been long criticized for forcing this meaningless subclassing. IIRC, starting with Rails 4 we will be able to drop in ActiveRecord persistence without inheriting from ActiveRecord::Base.

Hope this example makes a better case than the previous one.

from ambry.

tute avatar tute commented on September 27, 2024

It's the best code I've seen for my example, in which I want to have the persistance logic and add only one field. Thanks @xymbol for your response.

from ambry.

Related Issues (5)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.