Forum: Ruby shared-0.4.2

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
1bac2e65d64faf472cf2ebc94f0f5ee0?d=identicon&s=25 Ara Howard (ahoward)
on 2008-11-09 20:43
(Received via mailing list)
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/
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2008-11-09 21:49
(Received via mailing list)
ara howard wrote:
>
> NAME
>   shared.rb
...
> enjoy.

shared and enjoyed ;)
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2008-11-09 22:03
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 :)
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
1bac2e65d64faf472cf2ebc94f0f5ee0?d=identicon&s=25 Ara Howard (ahoward)
on 2008-11-09 22:35
(Received via mailing list)
On Nov 9, 2008, at 2:00 PM, Stefan Rusterholz wrote:

> Hi Ara
>
> Thanks a lot for sharing another of your fine libraries :)
> 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 ;-)  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/
1bac2e65d64faf472cf2ebc94f0f5ee0?d=identicon&s=25 Ara Howard (ahoward)
on 2008-11-09 22:37
(Received via mailing list)
On Nov 9, 2008, at 2:00 PM, Stefan Rusterholz wrote:

> Hi Ara
>
> Thanks a lot for sharing another of your fine libraries :)
> 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/
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2008-11-09 23:36
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
1bac2e65d64faf472cf2ebc94f0f5ee0?d=identicon&s=25 Ara Howard (ahoward)
on 2008-11-10 00:37
(Received via mailing list)
On Nov 9, 2008, at 3:33 PM, Stefan Rusterholz 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 ;-)

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/
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2008-11-10 00:39
Ara Howard wrote:
> On Nov 9, 2008, at 3:33 PM, Stefan Rusterholz 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 ;-)
>
> 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
1bac2e65d64faf472cf2ebc94f0f5ee0?d=identicon&s=25 Ara Howard (ahoward)
on 2008-11-10 01:43
(Received via mailing list)
On Nov 9, 2008, at 4:37 PM, Stefan Rusterholz 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 Rusterholz)

just pushed to rubyforge.

cheers.

a @ http://codeforpeople.com/
This topic is locked and can not be replied to.