Suggest alternatives for Facets paramix?

Discussion in 'Ruby' started by Jacob Burkhart, Mar 31, 2008.

  1. [Note: parts of this message were removed to make it a legal post.]

    I Can't seem to find any documentation or explanation as to why paramix has
    been forcibly deprecated from facets:
    http://facets.rubyforge.org/doc/changes.html

    And apparently that lack of documentation means not too many other people
    were making use of this cool tool.

    You see a similar technique used a lot in rails. For example, you'll add
    the make_resourceful plugin and now all of your controller have the class
    method make_resourceful. (And that takes some arguments) And when you call
    it ends up including some module from the plugin that adds things to your
    controller. great.

    But all of that takes a fair amount of up-front class_eval to add the
    make_resourceful class method to everything.

    For simple add-ons I like to use paramix.

    For example, I have a simple module called SqlSearch, and I do

    include SqlSearch, :eek:n => ['name', 'content']

    paramix gives me access to those hash parameters in my self.included(base)
    call in the module. So much simpler and cleaner than declaring class method
    everywhere, and there's a clear and definite association here. You KNOW to
    look for a SqlSearch module to find out what's going on I could instead
    have defined the sql_search class method on ActiveRecord::Base... but then
    I have to have require 'sql_search', I can't just have the const_missing
    SqlSearch trigger the load needed.... messiness?

    Anybody get what I'm talking about? Why get rid of such a useful thing?
    What's a good alternative?

    I debate making my own such thing, something like:

    include_mod SqlSearch, :eek:n => ['name', 'content']

    and then the callback is self.mod_included(base)... feels hackity


    Any thoughts?

    Jacob
    Jacob Burkhart, Mar 31, 2008
    #1
    1. Advertising

  2. Jacob Burkhart

    Trans Guest

    On Mar 31, 6:27 pm, "Jacob Burkhart" <> wrote:
    > I Can't seem to find any documentation or explanation as to why paramix has
    > been forcibly deprecated from facets:http://facets.rubyforge.org/doc/changes.html
    >
    > And apparently that lack of documentation means not too many other people
    > were making use of this cool tool.
    >
    > You see a similar technique used a lot in rails. For example, you'll add
    > the make_resourceful plugin and now all of your controller have the class
    > method make_resourceful. (And that takes some arguments) And when you call
    > it ends up including some module from the plugin that adds things to your
    > controller. great.
    >
    > But all of that takes a fair amount of up-front class_eval to add the
    > make_resourceful class method to everything.
    >
    > For simple add-ons I like to use paramix.
    >
    > For example, I have a simple module called SqlSearch, and I do
    >
    > include SqlSearch, :eek:n => ['name', 'content']
    >
    > paramix gives me access to those hash parameters in my self.included(base)
    > call in the module. So much simpler and cleaner than declaring class method
    > everywhere, and there's a clear and definite association here. You KNOW to
    > look for a SqlSearch module to find out what's going on I could instead
    > have defined the sql_search class method on ActiveRecord::Base... but then
    > I have to have require 'sql_search', I can't just have the const_missing
    > SqlSearch trigger the load needed.... messiness?
    >
    > Anybody get what I'm talking about? Why get rid of such a useful thing?
    > What's a good alternative?
    >
    > I debate making my own such thing, something like:
    >
    > include_mod SqlSearch, :eek:n => ['name', 'content']
    >
    > and then the callback is self.mod_included(base)... feels hackity
    >
    > Any thoughts?


    Hi Jacob,

    It was a bit premature of me to remove it. My apologies. I encountered
    some conflicts between it and other libs and had to reconsider it. The
    idea is great, no doubt. Unfortunately the implementation was invasive
    --it overrode #include and #extend. Considering it further I felt it
    would be better to deprecate it rather then continue to promote a non-
    robust lib; and I've already started on a new version. I'm hoping to
    manage a highly robust implementation with much the same interface,
    except using captialize methods rather than overriding #include. Eg.

    class X
    include PMix:)parm=>"foo")
    end

    I worked on it last night, but it's a tough nut. If you (or anyone
    else) is interested in implementing this please take a whack.
    Hopefully I can get it into next Facets release. (2.4.1 in a week or
    so).

    In the mean time I've include a copy of the old version below if you
    need a (copy and paste) fix asap.

    T.

    ---- Here's the old deprecated version of paramix.rb ----

    # TITLE:
    #
    # Parametric Mixins
    #
    # SUMMARY:
    #
    # Parametric Mixins provides parameters for mixin modules.
    #
    # COPYRIGHT:
    #
    # Copyright (c) 2005 Thomas Sawyer, George Moschovitis
    #
    # LICENSE:
    #
    # Ruby License
    #
    # This module is free software. You may use, modify, and/or
    redistribute this
    # software under the same terms as Ruby.
    #
    # This program is distributed in the hope that it will be useful,
    but WITHOUT
    # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS
    # FOR A PARTICULAR PURPOSE.
    #
    # AUTHORS:
    #
    # - Thomas Sawyer
    # - George Moschovitis

    require 'facets/module/name' # for basename

    # = Parametric Mixins
    #
    # Parametric Mixins provides parameters for mixin modules.
    # Module parameters can be set at the time of inclusion or extension,
    # then accessed via an instance method of the same name as the
    included
    # module.
    #
    # == Synopsis
    #
    # module Mixin
    # def hello
    # puts "Hello from #{Mixin:)name)}"
    # end
    # end
    #
    # class MyClass
    # include Mixin, :name => 'Ruby'
    # end
    #
    # m = MyClass.new
    # m.hello -> 'Hello from Ruby'
    #
    # You can view the full set of parameters via the #mixin_parameters
    # class method, which returns a hash keyed on the included modules.
    #
    # MyClass.mixin_parameters #=> {Mixin=>{:name=>'Ruby'}}
    # MyClass.mixin_parameters[Mixin] #=> {:name=>'Ruby'}
    #
    # To create _dynamic mixins_ you can use the #included callback
    # method along with mixin_parameters method like so:
    #
    # module Mixin
    # def self.included( base )
    # parms = base.mixin_parameters[self]
    # base.class_eval {
    # def hello
    # puts "Hello from #{parms:)name)}"
    # end
    # }
    # end
    # end
    #
    # More conveniently a new callback has been added,
    #included_with_parameters,
    # which passes in the parameters in addition to the base class/module.
    #
    # module Mixin
    # def self.included_with_parameters( base, parms )
    # base.class_eval {
    # def hello
    # puts "Hello from #{parms:)name)}"
    # end
    # }
    # end
    # end
    #
    # We would prefer to have passed the parameters through the #included
    callback
    # method itself, but implementation of such a feature is much more
    complicated.
    # If a reasonable solution presents itself in the future however, we
    will fix.

    class Module

    # Store for module parameters. This is local per module
    # and indexed on module/class included-into.
    def mixin_parameters ; @mixin_parameters ||= {} ; end

    alias_method :include_without_parameters, :include

    def include(*args)
    params = args.last.is_a?(Hash) ? args.pop : {}
    args.each do |mod|
    mixin_parameters[mod] = params
    if mod.basename
    define_method( mod.basename ) do |key|
    if params.key?(key)
    params[key]
    else
    super if defined?( super )
    end
    end
    end
    end
    r = include_without_parameters(*args)
    for mod in args
    if mod.respond_to?:)included_with_parameters)
    mod.included_with_parameters( self, params )
    end
    end
    r
    end

    alias_method :extend_without_parameters, :extend

    def extend(*args)
    params = args.last.is_a?(Hash) ? args.pop : {}
    args.each do |mod|
    (class << self; self; end).class_eval do
    mixin_parameters[mod] = params
    if mod.basename
    define_method( mod.basename ) do |key|
    if params.key?(key)
    params[key]
    else
    super if defined?( super )
    end
    end
    end
    end
    end
    r = extend_without_parameters(*args)
    for mod in args
    if mod.method_defined?:)extended_with_parameters)
    mod.extended_with_parameters( self, params )
    end
    end
    r
    end

    end
    Trans, Apr 1, 2008
    #2
    1. Advertising

  3. Jacob Burkhart

    Trans Guest

    On Mar 31, 7:34 pm, Trans <> wrote:
    > I worked on it last night, but it's a tough nut.


    Huh... it may have just a fallen into place. What do you think of:

    require 'facets/module/basename'
    require 'facets/module/modspace'

    module Paramix # or PatrametricMixin ?

    def self.append_features(base)
    base.modspace.module_eval %{
    def #{base.basename.to_s}(parameters, &block)
    Delegator.new(#{base}, parameters, &block)
    end
    }
    end

    # It you want to define the module method by hand. You
    # can use Parmix.new instead of Parmix::Delegator.new.

    def self.new(delegate_module, parameters={}, &base_block)
    Delegator.new(delegate_module, parameters, &base_block)
    end

    #

    class Delegator < Module

    attr :delegate_module
    attr :parameters
    attr :base_block

    def initialize(delegate_module, parameters={}, &base_block)
    @delegate_module = delegate_module
    @parameters = parameters
    @base_block = base_block
    end

    def append_features(base)
    base.__send__:)include, delegate_module)
    base.parametric_options[delegate_module] = parameters
    base.module_eval do
    define_method:)parametric_options) do
    base.parametric_options
    end
    end
    base.module_eval(&@base_block) if base_block
    end

    def [](name)
    @parameters[name]
    end

    end

    end


    class Module

    # Store for parametric mixin parameters.
    #
    # Returns a hash, the keys of which are the parametric mixin
    module
    # and the values are the parameters associacted with this module/
    class.
    #
    # class C
    # include P:)x=>1)
    # end
    #
    # C.parametric_options[P] #=> {:x=>1}
    #
    def parametric_options
    @parametric_options ||= {}
    end

    end

    # Try it out

    if __FILE__ == $0

    module O
    include Paramix

    def x
    parametric_options[O][:x]
    end
    end

    # If doing it by hand instead of using include Paramix.
    #def O(options)
    # Paramix.new(O, options)
    #end

    class X
    include O:)x=>1)
    end

    x = X.new
    p x.x

    p X.ancestors

    end


    T.
    Trans, Apr 1, 2008
    #3
  4. Jacob Burkhart

    ara.t.howard Guest

    On Mar 31, 2008, at 4:27 PM, Jacob Burkhart wrote:
    > But all of that takes a fair amount of up-front class_eval to add the
    > make_resourceful class method to everything.


    ??

    module SqlSearch

    def SqlSearch.bless other, options = {}
    stuff_with options
    other.send :include, self
    end

    end

    class Module
    def sqlsearch options = {}
    SqlSearch.bless self, options
    end
    end

    a @ http://codeforpeople.com/
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
    ara.t.howard, Apr 1, 2008
    #4
  5. [Note: parts of this message were removed to make it a legal post.]

    Hey Tran,

    Thanks for re-adding Paramix to facets!
    I seem to be getting a conflict with another thing called Delegator in
    class_eval.

    So this seems to work better:

    def self.append_features(base)
    base.modspace.module_eval %{
    def #{base.basename.to_s}(parameters, &block)
    Paramix::Delegator.new(#{base}, parameters, &block)
    end
    }
    end


    and I also had to change the order of things in append_features so that the
    include is last, because I want to be able to reference mixin_parameters in
    self.included:


    def append_features(base)
    base.mixin_parameters[delegate_module] = parameters

    base.module_eval do
    define_method:)mixin_parameters) do
    base.mixin_parameters
    end
    end

    base.__send__:)include, delegate_module)

    base.module_eval(&@base_block) if base_block
    end

    Can we get these changes in the next version of facets?

    thanks,
    Jacob

    On Mon, Mar 31, 2008 at 9:25 PM, ara.t.howard <>
    wrote:

    >
    > On Mar 31, 2008, at 4:27 PM, Jacob Burkhart wrote:
    >
    > > But all of that takes a fair amount of up-front class_eval to add the
    > > make_resourceful class method to everything.
    > >

    >
    > ??
    >
    > module SqlSearch
    >
    > def SqlSearch.bless other, options = {}
    > stuff_with options
    > other.send :include, self
    > end
    >
    > end
    >
    > class Module
    > def sqlsearch options = {}
    > SqlSearch.bless self, options
    > end
    > end
    >
    > a @ http://codeforpeople.com/
    > --
    > we can deny everything, except that we have the possibility of being
    > better. simply reflect on that.
    > h.h. the 14th dalai lama
    >
    >
    >
    >
    >
    Jacob Burkhart, Apr 7, 2008
    #5
  6. Jacob Burkhart

    Trans Guest

    On Apr 7, 2:50 pm, "Jacob Burkhart" <> wrote:
    > Hey Tran,
    >
    > Thanks for re-adding Paramix to facets!
    > I seem to be getting a conflict with another thing called Delegator in
    > class_eval.
    >
    > So this seems to work better:
    >
    > def self.append_features(base)
    > base.modspace.module_eval %{
    > def #{base.basename.to_s}(parameters, &block)
    > Paramix::Delegator.new(#{base}, parameters, &block)
    > end
    > }
    > end


    Ah, good catch, I will fix.

    > and I also had to change the order of things in append_features so that the
    > include is last, because I want to be able to reference mixin_parameters in
    > self.included:
    >
    > def append_features(base)
    > base.mixin_parameters[delegate_module] = parameters
    >
    > base.module_eval do
    > define_method:)mixin_parameters) do
    > base.mixin_parameters
    > end
    > end
    >
    > base.__send__:)include, delegate_module)
    >
    > base.module_eval(&@base_block) if base_block
    > end


    Yep. I ran into that too and have already made that change.

    > Can we get these changes in the next version of facets?


    Yep. And I will be releasing 2.4.2 in a matter of days.

    Thanks Jacob,
    T.
    Trans, Apr 7, 2008
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Nate
    Replies:
    4
    Views:
    480
  2. David List
    Replies:
    0
    Views:
    291
    David List
    Aug 6, 2003
  3. Roger Leigh
    Replies:
    4
    Views:
    454
    Roger Leigh
    Nov 12, 2003
  4. Replies:
    0
    Views:
    382
  5. Trans

    Paramix

    Trans, Apr 5, 2008, in forum: Ruby
    Replies:
    0
    Views:
    73
    Trans
    Apr 5, 2008
Loading...

Share This Page