Suggest alternatives for Facets paramix?

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, :on => [‘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, :on => [‘name’, ‘content’]

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

Any thoughts?

Jacob

On Mar 31, 6:27 pm, “Jacob B.” [email protected] wrote:

controller. great.
paramix gives me access to those hash parameters in my self.included(base)
I debate making my own such thing, something like:

include_mod SqlSearch, :on => [‘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 S., George M.

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 S.

- George M.

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

On Mar 31, 2008, at 4:27 PM, Jacob B. 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/

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 [email protected]

On Mar 31, 7:34 pm, Trans [email protected] 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.

On Apr 7, 2:50 pm, “Jacob B.” [email protected] wrote:

  def #{base.basename.to_s}(parameters, &block)
    Paramix::Delegator.new(#{base}, parameters, &block)
  end
}

end

Ah, good catch, I will fix.

    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.