Shared-0.4.2


#1

NAME
shared.rb

DESCRIPTION
super simple super power sharing of instance and class level code

INSTALL
gem install shared

URIS
http://rubyforge.org/projects/codeforpeople
http://codeforpeople.com/lib/ruby/

HISTORY
0.4.2
initial version

SAMPLES

<========< samples/a.rb >========>

~ > cat samples/a.rb

 # shared.rb is a very simple and very powerful method of sharing

code between
# classes.
#
require ‘shared’

   shared(:code) do
     def classname() self.class.name end
   end

   class Foo
     include shared(:code)
   end

   class Bar
     include shared(:code)
   end

   p Foo.new.classname #=> "Foo"

   p Bar.new.classname #=> "Bar"

~ > ruby samples/a.rb

 "Foo"
 "Bar"

<========< samples/b.rb >========>

~ > cat samples/b.rb

 # shared.rb allows natural declaration of both instance and class-

level
# methods - it’s more than simple module inclusion
#

   require 'shared'

   shared('methods') do
     def self.class_method() 40 end

     def instance_method() 2 end
   end

   class C
     include shared('methods')
   end

   p(C.class_method + C.new.instance_method) #=> 42

~ > ruby samples/b.rb

 42

<========< samples/c.rb >========>

~ > cat samples/c.rb

 # shared.rb works equally well with individual objects in

addition to the
# normal class level usage
#

   require 'shared'

   shared(:meta_tools) do
     def singleton_class &block
       singleton_class =
         class << self
           self
         end
       block ? singleton_class.module_eval(&block) : singleton_class
     end
   end

   a = %w( a b c )

   a.extend shared(:meta_tools)

   a.singleton_class do
     def to_range() first .. last end
   end

   p a.to_range #=> "a".."c"

~ > ruby samples/c.rb

 "a".."c"

<========< samples/d.rb >========>

~ > cat samples/d.rb

 # an example use-case for shared.rb is sharing code bewteen

classes that
# require both class level and instance level behaviour to be
shared
#

   require 'shared'

   shared(:acts_as_named) do
     validates_precence_of :name

     def to_html() "<blink> #{ name } </blink>" end
   end

   class Model
     def Model.validates_precence_of(*a) end

     def name() 'zaphod' end

     include shared(:acts_as_named)
   end

   p Model.new.to_html #=> "<blink> zaphod </blink>"

~ > ruby samples/d.rb

 "<blink> zaphod </blink>"

<========< samples/e.rb >========>

~ > cat samples/e.rb

 # it's important to note that the shared code is injected into

the reciever
# fresh on each call and, in that way, the effect is rather macro
like
#

   require 'shared'

   share(:instance_tracker) do
     const_set :Instances, []

     def self.instances() const_get :Instances end

     def self.new *a, &b
       obj = super
     ensure
       instances << obj
     end
   end

   class Foo
     include shared(:instance_tracker)
   end

   class Bar
     include shared(:instance_tracker)
   end

   2.times{ Foo.new }
   40.times{ Bar.new }

   p(Foo.instances.size + Bar.instances.size)

~ > ruby samples/e.rb

 42

enjoy.

a @ http://codeforpeople.com/


#2

ara howard wrote:

NAME
shared.rb

enjoy.

shared and enjoyed :wink:


#3

Ara Howard wrote:

NAME
shared.rb

DESCRIPTION
super simple super power sharing of instance and class level code

Hi Ara

Thanks a lot for sharing another of your fine libraries :slight_smile:
May I ask why I would introduce the dependency ‘shared’ instead of using
rubys native code sharing facility that is inheritance and (IMO more
powerful) modules? Where do you see the striking advantages of shared?

Regards
Stefan


#4

On Nov 9, 2008, at 2:00 PM, Stefan R. wrote:

Hi Ara

Thanks a lot for sharing another of your fine libraries :slight_smile:
May I ask why I would introduce the dependency ‘shared’ instead of
using
rubys native code sharing facility that is inheritance and (IMO more
powerful) modules? Where do you see the striking advantages of shared?

Regards
Stefan

well, for starters it is based on modules :wink: the striking
advantage is, as a for instance, that you can do this in rails

in lib/shared.rb

shared :before_filters do
before_filter :foo
before_filter :bar

def foo() end
def bar() end
end

in app/controllers/foo_controller.rb

class Foo < ApplicationController
include shared(:before_filters)
end

in app/controllers/bar/controller.rb

class Bar < ApplicationController
include shared(:before_filters)
end

this is absolutely not easily done with modules. shared.rb has all
the advantages of ruby module sharing plus the simplicity of
completely POLS class level method sharing.

another example, which is not easily done using modules

in lib/shared.rb

shared :home_controller do
before_filter :must_have_user

def index
render ‘shared/home’
end

protected
def must_have_user() end
end

in app/controllers/teacher/home_controller.rb

class Teacher::HomeController < ApplicationController
include shared(:home_controller)
end

in app/controllers/student/home_controller.rb

class Student::HomeController < ApplicationController
include shared(:home_controller)
end

so, in that example, we can directly setup a public method (index
action) and protected method, and call a class method. try doing that
with modules and you’ll see that it’s rather un-natural. the call to
before_filter, for instance, cannot simply be wrapped with the normal
‘ClassMethods’ hack, but must actually be deferred because it only
exists in the target classes - aka it doesn’t exist in the mixin but
only exists in the mixxee (controllers) making it a chicken-and-egg
issue when code sharing is desired.

shared let’s you factor out chunks of code exactly as you would have
typed them before and then, later, to inject them into classes or
module or objects exactly as if you’d entered the code there

make sense?

cheers.
a @ http://codeforpeople.com/


#5

On Nov 9, 2008, at 2:00 PM, Stefan R. wrote:

Hi Ara

Thanks a lot for sharing another of your fine libraries :slight_smile:
May I ask why I would introduce the dependency ‘shared’ instead of
using
rubys native code sharing facility that is inheritance and (IMO more
powerful) modules? Where do you see the striking advantages of shared?

Regards
Stefan

one last thing - shared.rb is only 44 lines of code so i really don’t
expect you to introduce a dependancy, rather i expect you to steal it
and drop it into your project’s lib dir and be done with it. it’s
small enough to simply cut and paste into any existing project as well.

if you want to depend on it, however, the gem makes it easy.

cheers.

a @ http://codeforpeople.com/


#6

Ara Howard wrote:

shared :before_filters do
before_filter :foo
before_filter :bar

def foo() end
def bar() end
end

in app/controllers/foo_controller.rb

class Foo < ApplicationController
include shared(:before_filters)
end

in app/controllers/bar/controller.rb

class Bar < ApplicationController
include shared(:before_filters)
end

module SharedBeforeFilters
def self.included(by)
by.before_filter :foo
by.before_filter :bar
end

def foo(); end
def bar(); end
end

in app/controllers/foo_controller.rb
class Foo < ApplicationController
include SharedBeforeFilters
end

in app/controllers/bar_controller.rb
class Bar < ApplicationController
include SharedBeforeFilters
end

this is absolutely not easily done with modules.

I don’t see the problem here.

shared.rb has all

the advantages of ruby module sharing plus the simplicity of
completely POLS class level method sharing.

another example, which is not easily done using modules

in lib/shared.rb

shared :home_controller do
before_filter :must_have_user

def index
render ‘shared/home’
end

protected
def must_have_user() end
end

in app/controllers/teacher/home_controller.rb

class Teacher::HomeController < ApplicationController
include shared(:home_controller)
end

in app/controllers/student/home_controller.rb

class Student::HomeController < ApplicationController
include shared(:home_controller)
end

so, in that example, we can directly setup a public method (index
action) and protected method, and call a class method. try doing that
with modules and you’ll see that it’s rather un-natural.

module HomeController
def self.included(by)
by.before_filter :must_have_user
end

def index
render ‘shared/home’
end

protected
def must_have_user() end
end

in app/controllers/teacher/home_controller.rb
class Teacher::HomeController < ApplicationController
include HomeController
end

in app/controllers/student/home_controller.rb
class Student::HomeController < ApplicationController
include HomeController
end

Again, I don’t see the issue. But maybe I miss the obvious or something
:-/

make sense?

Not sure yet. But thanks for the explanations!

Regards
Stefan


#7

Ara Howard wrote:

On Nov 9, 2008, at 3:33 PM, Stefan R. wrote:

Again, I don’t see the issue. But maybe I miss the obvious or
something

what you are missing is that you are good @ ruby :wink:

seriously though, it really does get messy with class instance vars
and especially @@class vars. shared just let’s you forget about it.
mostly it’s motivated by me getting sick of writing ‘included’ hooks
and ‘class << other’ - that’s it.

cheers.

a @ http://codeforpeople.com/

Ok. Then one request:
Add the global methods to Kernel instead of Object (as they are, as I
understand them, quasi-global methods and not instance methods) and make
them private (to not disable method_missing for them).

Regards
Stefan


#8

On Nov 9, 2008, at 3:33 PM, Stefan R. wrote:

Again, I don’t see the issue. But maybe I miss the obvious or
something

what you are missing is that you are good @ ruby :wink:

seriously though, it really does get messy with class instance vars
and especially @@class vars. shared just let’s you forget about it.
mostly it’s motivated by me getting sick of writing ‘included’ hooks
and ‘class << other’ - that’s it.

cheers.

a @ http://codeforpeople.com/


#9

On Nov 9, 2008, at 4:37 PM, Stefan R. wrote:

Ok. Then one request:
Add the global methods to Kernel instead of Object (as they are, as I
understand them, quasi-global methods and not instance methods) and
make
them private (to not disable method_missing for them).

both good ideas. done.

HISTORY 0.4.3
- added version info
- move methods from Object to Kernel and made them private (thx
Stefan R.)

just pushed to rubyforge.

cheers.

a @ http://codeforpeople.com/