Suggest alternatives for Facets paramix?

J

Jacob Burkhart

[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
 
T

Trans

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
 
T

Trans

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

ara.t.howard

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/
 
J

Jacob Burkhart

[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
 
T

Trans

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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Suggest a quick script for an idea I have? 0
ANN: Facets 2.0 12
[ANN] Facets 1.8 4
[ANN] Facets / Annotations 2.0.0 1
Paramix 0
[ANN] Facets / Multiton 2.0.0 2
[ANN] Facets 2005-10-30 9
[Facets] Range#overlap? 21

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top