logo       

Re: RESTful mixin, mixin repo?: msg#00027

lang.ruby.camping.general

Subject: Re: RESTful mixin, mixin repo?

Mark Fredrickson wrote:
> [...] I want: entire MVC stacks that I can drop into different apps -
> eg. a user login engine that works in any app a /user and provides
> some useful predicates - is_logged_in?, etc...)

I've had a look at this and think I've found something like a
solution. The Controllers and Models don't seem to be much of an
issue, the Views are a little more problematic. Read on for the
details.

# Views

Camping.goes :NewApp
module NewApp
module Views; include OtherApp::Views; end
end

Doesn't work because NewApp::Views is included into NewApp::Mab
*before* the inclusion of OtherApp::Views. As a result the
OtherApp::Views methods are *not* included in the NewApp::Mab class
and so are not available for controllers/other view methods to call. At
least I *think* that's what's happening.

Camping.goes :NewApp
module NewApp
class Mab; include OtherApp::Views; end
end

Works, but you can't override OtherApp's views in NewApp. If
OtherApp includes a layout then you're stuck with it (unless you
change it under the Mab class in NewApp rather than Views).

# Create the NewApp module and include the OtherApp's Views into it
module NewApp
module Views; include OtherApp::Views; end
end

# Stir in Camping goodness
Camping.goes :NewApp

# Write the NewApp, freely using the views from OtherApp
module NewApp
# ... models, views, controllers, etc.
end

Works, and is somewhat less coupled to Camping's implementation. A
benefit of this is that you can override any of OtherApp's views in
NewApp (e.g. overriding the layout) without leaving the cosy
confines of the Views module.

# Controllers

Camping.goes :NewApp
module NewApp
module Controllers; include OtherApp::Controllers; end
end

Works.

Doing the include before Camping.goes, as in Views above, also
works.

# Models

Camping.goes :NewApp
module NewApp
module Models; include OtherApp::Models; end
include OtherApp # for the create method
end

Doesn't work -- the OtherApp.create singleton method isn't included
into NewApp (due to the way include works).

Camping.goes :NewApp
module NewApp
module Models; include OtherApp::Models; end
def self.create
Models.create_schema
end
end

Doesn't work, the OtherApp tables don't get created. create_schema
doesn't see the schema from OtherApp for some reason.

Camping.goes :NewApp
module NewApp
module Models; include OtherApp::Models; end
def self.create
OtherApp::Models.create_schema
end
end

Works. Tables are created and models from OtherApp can be used in
NewApp.

Doing the include, and defining self.create, before Camping.goes, as
in Views above, also works.

# Putting it all together

See the attached: campers.rb and campfire.rb.

campers.rb is a simple app that exposes a list of campers, campfire.rb
extends this with another controller and view, please excuse the
campness of it all.

The main ingredient is the means by which Campfire includes Campers:

module Campfire
module Models; include Campers::Models; end
module Controllers; include Campers::Controllers; end
module Views; include Campers::Views; end
module Helpers; include Campers::Helpers; end

def self.create; Campers.create; end
end

This comes *before* the `Camping.goes :Campfire` line.

So, if you want to incorporate one Camping app within another the above
method seems to be the way to go. Seems a bit verbose though and I
don't like that whole "you have to extend the new application before
creating it with Camping.goes" thing. How about coercing include
to help us out a bit?

module Campers
def self.included(other_app)
%w{Helpers Models Controllers Views}.each do |mod|
next unless self.const_defined? mod
unless other_app.const_defined? mod
other_app.const_set(mod, Module.new)
end

our_mod = self.const_get(mod)
other_app.const_get(mod).class_eval(){include our_mod}
end

if !other_app.method_defined?('create') \
&& self.method_defined?('create')
other_app.class_eval(
"def self.create; #{self.name}.create; end"
)
end
end
end

Hmmm. That's decidedly *more* verbose. But we can now do this:

module Campfire; include Campers; end
Camping.goes :Campfire
# ... Campfire models, views, controllers, etc.

So, if we can hide that great big chunk of `included` somewhere out of
sight, but where Camping apps can pick it up, we'd be somewhere near to
where we want to be.

--
Adam

Attachment: campers.rb
Description: application/ruby

Attachment: campfire.rb
Description: application/ruby

_______________________________________________
Camping-list mailing list
Camping-list-GrnCvJ7WPxnNLxjTenLetw@xxxxxxxxxxxxxxxx
http://rubyforge.org/mailman/listinfo/camping-list
<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise