Git Product home page Git Product logo

Comments (17)

dkubb avatar dkubb commented on June 28, 2024

@emmanuel I think you've mentioned in the past that subclassing Module is a little known, but powerful technique. Do you mind commenting on some specifics?

from virtus.

solnic avatar solnic commented on June 28, 2024

@hookercookerman you need to create an instance of that module subclass and include it then. For example:

class MyModule < Module
  def foo
  end
end

class A
  include MyModule.new
end

A.new.foo

This technique is our small experiment that was started by @emmanuel. Subclassing modules allowed us to clean up various pieces of Virtus. The general idea is that a module subclass is aware of a special behavior that's required when the module gets included in a class. Previously we had a class that would include a module into something and perform other extra work - now we have a module that performs this work which results in better encapsulation. Or at least we think it does :)

I'm sure @emmanuel has more to say about this though

from virtus.

blambeau avatar blambeau commented on June 28, 2024

I remember @dkubb's answer to a similar question a few weeks ago: https://twitter.com/dkubb/status/211106940879781889
It made perfect sense to me at that time (and still does, in fact)

from virtus.

hookercookerman avatar hookercookerman commented on June 28, 2024

Thanks for the feedback having trouble running your example

I am using 1.9.3p194

class MyModule < Module
  def foo
  end
end

class A
  include MyModule.new
end
 A.new.foo

undefined method `foo' for #<A:0x007fbd8487c8c0> (NoMethodError)

from virtus.

solnic avatar solnic commented on June 28, 2024

@hookercookerman ugh. right - my bad. you'd have to define included hook and extend/include other modules there if you want

In Virtus the attribute set is now a module subclass which knows how to define attribute readers and writes on a class that included it. I agree it looks weird because nobody is using such approach but I like how it cleaned up the code which makes me think it's a neat solution.

We'll see how it works - as I said we're experimenting with this approach :)

from virtus.

hookercookerman avatar hookercookerman commented on June 28, 2024

sorry on last thing; no worries if no as this is a bit out there;

I have 95% ported virtus to work with rubymotion; motion does not support subclassing of modules what would be the approach for attributeSet and Equalizer that you would implement if you did not have use of this feature; just enough info to send me down the right path would be cool

cheers

from virtus.

hookercookerman avatar hookercookerman commented on June 28, 2024

I keep looking at the source to try to untangle what is going on; if the subclass of a module cannot include methods that it defines; and the subclass itself does not have a self.included method that I cant see what it does; I am hoping for an epiphany moment.

I like to read code I can understand

I would like to understand this but I cannot; more ruby foo is required be me;

cheers

from virtus.

solnic avatar solnic commented on June 28, 2024

@hookercookerman it dynamically defines methods that's why there's no included hook. See here

from virtus.

emmanuel avatar emmanuel commented on June 28, 2024

Every time you use the module keyword to create a module (as opposed to reopening an existing module) Ruby creates an instance of the class Module. The only state retained by a module created this way is the set of instance methods it holds that can be inserted into the method lookup chain via include and extend.

With a subclass of Module, you are free to design the class so that instances of it (which are themselves modules) hold additional state beyond the set of instance methods. It gets a bit confusing when thinking about instances of a Module subclass having instance methods (defined in the class body, as usual), and holding instance methods.

So far it looks like this pattern is most useful when you would otherwise use an anonymous module (eg., using Module.new), where the anonymous module has instance methods dynamically defined (eg., with define_method or module_eval).

AttributeSet is the furthest that I've pushed the idea so far. In that case, AttributeSet instances hold references to Attribute instances and the methods to use them (getters & setters). Previously there were separate collection and module objects.

Hope that helps.

On Jul 26, 2012, at 4:30 AM, Piotr [email protected] wrote:

@hookercookerman it dynamically defines methods that's why there's no included hook. See here


Reply to this email directly or view it on GitHub:
#106 (comment)

from virtus.

hookercookerman avatar hookercookerman commented on June 28, 2024

super thanks for the reply really helps; I am like oooooh I see it now; so thats cool.

I always thought it was not even a feature

http://www.rubyist.net/~slagell/ruby/modules.html

I was really close to getting this library working on rubymotion (not easy); as I think it will really help with people creating mappers for core data and dealing with rest; just a good lib to work on top of basically;

but isubclassing a Module does not work in motion :( I tried to circumvent this but my head nearly exploded.

Cheers

from virtus.

solnic avatar solnic commented on June 28, 2024

@hookercookerman I'm happy to help you with this. Virtus used to have "a traditional" approach to this which means we used anonymous modules. I think it should be possible to build a compatibility layer for RubyMotion using same techniques as we used to have.

It would be a matter of using a separate strategy for attribute set and defining attribute accessors and a separate class for Equalizer - both would be only used in RubyMotion environment. This would mean using the previous version of AttributeSet class, overriding extended and inherited hooks so that they no longer include attribute_set module instance and falling back to using anonymous modules for defining accessors.

You can take a look at older versions of Virtus to see how we used anonymous modules to define attribute accessors.

I'm not sure how we should handle class loading. I guess you could remove AttributeSet and Equalizer constants and provide your own that will work with RubyMotion.

from virtus.

hookercookerman avatar hookercookerman commented on June 28, 2024

cheers you guys are helpful cool; I will give this a whirl and take a look at the older version; cheers

from virtus.

dkubb avatar dkubb commented on June 28, 2024

I'm going to mark this issue as closed.

from virtus.

lovehandle avatar lovehandle commented on June 28, 2024

Giving this another shot, for the record. I have the project up at this repository.

@hookercookerman is dead on - RubyMotion does not support subclassing of modules, and getting Virtus to work with it was not trivial. I have the project building correctly now (though there are still a few bugs I'm trying to squash). I'm temporarily using a workaround for the subclassing of modules, but I'll need to come up with a better solution shortly.

As a sidenote - that's a really clean approach. @solnic, I'd read your blog post, but it makes a lot more sense in the context of a project.

from virtus.

solnic avatar solnic commented on June 28, 2024

@rclosner do you know why RubyMotion doesn't support it? Is it not possible to implement?

from virtus.

lovehandle avatar lovehandle commented on June 28, 2024

@solnic i really don't know. it definitely recognizes the syntax as valid, but it could be that it's slated for later release. i'm only 3 days into RM... can't really speak authoritatively on the subject yet. :)

Everything appears to be in working order for motion_virtus, though. I have one more bug to fix with method visibility not working, then it should be good to go.

One thing I noticed (tangentially) is that coercible raises an error if it can't find the appropriate coercion method. While I think that's a better solution than returning the value (like it was before), it gets obnoxious when you're just trying to instantiate an empty object.

class User
  include Virtus
  attribute :name, String
end

User.new
#=> UnsupportedCoercion: Coercible::Coercer::Object#to_string doesn't know how to coerce nil.

Are you planning on adding a NilClass coercer, or will users have to handle this case manually?

from virtus.

solnic avatar solnic commented on June 28, 2024

@rclosner that's a bug please report

from virtus.

Related Issues (20)

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.