-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Class reopening and inheritance. #161
base: master
Are you sure you want to change the base?
Class reopening and inheritance. #161
Conversation
I would expect this to succeed, so I say it's a bug. |
edb14f9
to
4f95c65
Compare
4f95c65
to
56ae19e
Compare
Lets see, I have a working solution now but I don't like it for some reasons. I introduced But I don't like the way how def self.inherited_entities
sclass = class << self; self; end
ObjectSpace.each_object(sclass).to_set.delete(self)
end I like this much more because I don't want to store child classes in array. Because when someone call Solution with
I can detect if running under JRuby and determine child classes using There's also a problem with unexposures since we have this spec: subject.expose :name, :email
child_class = Class.new(subject)
subject.unexpose :email
expect(subject.root_exposures.length).to eq 1
expect(subject.root_exposures[0].attribute).to eq :name
expect(child_class.root_exposures[0].attribute).to eq :name
expect(child_class.root_exposures[1].attribute).to eq :email They're expected to not affect children but exposures are. So it won't be intuitive if some things are truly inheritable but some other are just half inheritable (unexposures). I propose to make this things behave identical: remove the spec I mentioned above and make exposures, unexposures and formatters be inheritable. But since it's a breaking change just put it only to 0.5 since it's already breaking. And of course describe this change in UPGRADING. |
The code that's here is a lot simpler than what you're describing and |
It could be buggy with code reloading feature but I'm not sure. Depends on how it's implemented. Ideally, class object should be referenced only by a constant to which it's assigned. But this implementation references class also in |
Oh, there's another reason not to choose this way at all. class A < Grape::Entity
expose :x
end
class B < A
expose :z
end
A.expose :y In current implementation So I need to invent a new solution. |
So my intuition is that anything that happens in the parent class should be "prepended" to the child class — exposures, unexposures, formatters, etc. Even if I reopen parent class after inheritance. |
Oh my. I feel largely unqualified to make calls here. I think in your example I would survive the current behavior just fine, of |
Exposures and formatters should appear in inherited classes even if added after inheriting.
56ae19e
to
30aa970
Compare
Lets describe it in terms of RSpec: it 'puts exposures in the right order' do
subject.expose :x
child_class = Class.new(subject) do
expose :z
end
subject.expose :y
object = {
x: 1,
y: 2,
z: 3
}
expect(child_class.represent(object, serializable: true).keys).to eq([:x, :y, :z])
end
it 'just prepends parent class exposures to the inherited class' do
subject.expose :x
child_class = Class.new(subject) do
expose :y, proc: -> (_obj, _opts) { 'specific' }
end
subject.expose :y
object = {
x: 1,
y: 2
}
expect(child_class.represent(object, serializable: true)).to eq(x: 1, y: 'specific')
end This two new specs are not satisfied https://travis-ci.org/ruby-grape/grape-entity/jobs/74816055. |
Maybe it's just a corner case but maybe not.
I also think it could be related to #120 but I'm not sure.