puffer 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2010 puffer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = Puffer
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rake'
10
+ require 'rake/rdoctask'
11
+
12
+ require 'rspec/core'
13
+ require 'rspec/core/rake_task'
14
+
15
+ RSpec::Core::RakeTask.new(:spec)
16
+
17
+ task :default => :spec
18
+
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'rdoc'
21
+ rdoc.title = 'Puffer'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('README.rdoc')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
26
+
27
+ require 'jeweler'
28
+
29
+ Jeweler::Tasks.new do |gem|
30
+ gem.name = "puffer"
31
+ gem.summary = %Q{Admin interface generator}
32
+ gem.description = %Q{Puffer}
33
+ gem.email = "kinwizard@gmail.com"
34
+ gem.homepage = "http://github.com/puffer/puffer"
35
+ gem.authors = ["pyromaniac"]
36
+ end
@@ -0,0 +1,18 @@
1
+ Description:
2
+ Create puffer controller for specified model
3
+
4
+ Example:
5
+ rails generate puffer:controller User
6
+ rails generate puffer:controller user
7
+ rails generate puffer:controller users
8
+
9
+ This will create:
10
+ app/controllers/admin/users_controller.rb
11
+
12
+ rails generate puffer:controller Moderator::User
13
+ rails generate puffer:controller moderator/user
14
+ rails generate puffer:controller moderator/users
15
+
16
+ This will create:
17
+ app/controllers/moderator/users_controller.rb
18
+
@@ -0,0 +1,21 @@
1
+ class Puffer::ControllerGenerator < Rails::Generators::NamedBase
2
+ source_root File.expand_path('../templates', __FILE__)
3
+
4
+ def generate_controller
5
+ @modules = name.classify.split('::')
6
+ @model_name = @modules.delete_at(-1)
7
+
8
+ template('controller.rb', "app/controllers/#{controller_name.underscore}_controller.rb")
9
+ end
10
+
11
+ private
12
+
13
+ def controller_name
14
+ ((@modules.presence || ['Admin']) << @model_name.pluralize).join('::')
15
+ end
16
+
17
+ def attributes
18
+ @model_name.constantize.columns.map(&:name)
19
+ end
20
+
21
+ end
@@ -0,0 +1,16 @@
1
+ class <%= controller_name %>Controller < Puffer::Base
2
+ before_filter :i_didnt_forget_to_protect_this
3
+
4
+ index do
5
+ <% attributes.each do |attribute| -%>
6
+ field :<%= attribute %>
7
+ <% end -%>
8
+ end
9
+
10
+ form do
11
+ <% attributes.each do |attribute| -%>
12
+ field :<%= attribute %>
13
+ <% end -%>
14
+ end
15
+
16
+ end
@@ -0,0 +1,6 @@
1
+ Description:
2
+ Copy puffer files to your application
3
+
4
+ Example:
5
+ rails generate puffer:install
6
+
@@ -0,0 +1,3 @@
1
+ class Puffer::InstallGenerator < Rails::Generators::Base
2
+ source_root File.expand_path('../templates', __FILE__)
3
+ end
@@ -0,0 +1,46 @@
1
+ module Puffer
2
+ class Base < ApplicationController
3
+ unloadable
4
+
5
+ respond_to :html
6
+
7
+ include Puffer::Controller::Mutate
8
+ include Puffer::Controller::Dsl
9
+ include Puffer::Controller::Helpers
10
+
11
+ def index
12
+ @records = current_resource.collection
13
+ end
14
+
15
+ def show
16
+ @record = current_resource.member
17
+ end
18
+
19
+ def new
20
+ @record = current_resource.new_member
21
+ end
22
+
23
+ def edit
24
+ @record = current_resource.member
25
+ end
26
+
27
+ def create
28
+ @record = current_resource.new_member
29
+ @record.save
30
+ respond_with @record, :location => current_resource.path
31
+ end
32
+
33
+ def update
34
+ @record = current_resource.member
35
+ @record.update_attributes current_resource.attributes
36
+ respond_with @record, :location => current_resource.path
37
+ end
38
+
39
+ def destroy
40
+ @record = current_resource.member
41
+ @record.destroy
42
+ redirect_to current_resource.path
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,79 @@
1
+ module Puffer
2
+ module Controller
3
+ module Actions
4
+
5
+ def self.included base
6
+ base.class_eval do
7
+ extend ClassMethods
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ def generate_association_actions field
14
+ field.collection? ? generate_collection_association_actions(field) : generate_single_association_actions(field)
15
+ end
16
+
17
+ def generate_single_association_actions field
18
+ define_method "associated_#{field}_choosing" do
19
+ @record = model.find params[:id]
20
+ @records = field.association.klass.scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
21
+ @field = field
22
+ render 'puffer/associated/one'
23
+ end
24
+ end
25
+
26
+ def generate_collection_association_actions field
27
+ define_method "associated_#{field}" do
28
+ @record = model.find params[:id]
29
+ @records = field.association.klass.scoped(:conditions => {:id => params[:ids]}).scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
30
+ @field = field
31
+ render 'puffer/associated/many'
32
+ end
33
+
34
+ define_method "associated_#{field}_choosing" do
35
+ @record = model.find params[:id]
36
+ @records = field.association.klass.scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
37
+ @choosen = field.association.klass.scoped(:conditions => {:id => params[:ids]}).scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
38
+ @field = field
39
+ render 'puffer/associated/many'
40
+ end
41
+ end
42
+
43
+ def generate_change_actions field
44
+ define_method "toggle_#{field}" do
45
+ @record = model.find params[:id]
46
+ @field = field
47
+ @record.toggle! field.name.to_sym
48
+ render 'puffer/toggle'
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def route_member_actions
55
+ unless @route_member_actions
56
+ @route_member_actions = {}
57
+ actions.each do |action|
58
+ @route_member_actions.merge!(action => :get)
59
+ end
60
+ [:form_fields, :update_fields, :create_fields].each do |fields|
61
+ fields = send fields
62
+ fields.each do |field|
63
+ if field.association?
64
+ field.collection? ? @route_member_actions.merge!("associated_#{field}" => :get, "associated_#{field}_choosing" => :get) : @route_member_actions.merge!("associated_#{field}_choosing" => :get)
65
+ end
66
+ end if fields
67
+ end
68
+ index_fields.each do |field|
69
+ @route_member_actions.merge!("toggle_#{field}" => :post) if field.toggable?
70
+ end if index_fields
71
+ end
72
+ @route_member_actions
73
+ end
74
+
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,28 @@
1
+ module Puffer
2
+ module Controller
3
+ class Config
4
+
5
+ attr_accessor :config
6
+ cattr_accessor :default_config
7
+ @@default_config = {}
8
+
9
+ def initialize
10
+ @config = {}
11
+ end
12
+
13
+ def self.option name, default
14
+ @@default_config[name.to_sym] = default
15
+ class_eval <<-EOS
16
+ def #{name} value = nil
17
+ value.nil? ? (@config.key?(:#{name}) ? @config[:#{name}] : self.class.default_config[:#{name}]) : @config[:#{name}] = value
18
+ end
19
+ EOS
20
+ end
21
+
22
+ option :destroy, true
23
+ option :model, nil
24
+ option :scope, {}
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,67 @@
1
+ module Puffer
2
+ module Controller
3
+ module Dsl
4
+
5
+ def self.included base
6
+ base.class_eval do
7
+ class_attribute :puffer_fields
8
+ self.puffer_fields = {}
9
+
10
+ extend ClassMethods
11
+
12
+ helper_method :index_fields, :show_fields, :form_fields, :create_fields, :update_fields
13
+ end
14
+ end
15
+
16
+ [:index, :show, :form, :create, :update].each do |sym|
17
+ define_method "#{sym}_fields" do
18
+ self.class.send "#{sym}_fields"
19
+ end
20
+ end
21
+
22
+ module ClassMethods
23
+
24
+ def configure &block
25
+ block.bind(current_config).call
26
+ end
27
+
28
+ [:index, :show, :form, :create, :update].each do |sym|
29
+ define_method sym do
30
+ @puffer_option = sym
31
+ yield if block_given?
32
+ end
33
+ end
34
+
35
+ def index_fields
36
+ puffer_fields[:index] || []
37
+ end
38
+
39
+ def show_fields
40
+ puffer_fields[:show] || puffer_fields[:index] || []
41
+ end
42
+
43
+ def form_fields
44
+ puffer_fields[:form] || []
45
+ end
46
+
47
+ def create_fields
48
+ puffer_fields[:create] || puffer_fields[:form] || []
49
+ end
50
+
51
+ def update_fields
52
+ puffer_fields[:update] || puffer_fields[:form] || []
53
+ end
54
+
55
+ def field name, options = {}
56
+ puffer_fields[@puffer_option] ||= []
57
+ field = ::Puffer::Field.new(current_resource.model, name, options)
58
+ generate_association_actions field if field.association?
59
+ generate_change_actions field if field.toggable?
60
+ puffer_fields[@puffer_option] << field
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,34 @@
1
+ module Puffer
2
+ module Controller
3
+ module Helpers
4
+
5
+ def self.included base
6
+ base.class_eval do
7
+ helper_method :resource_session, :searchable_fields, :boolean_fields, :puffer_navigation
8
+ end
9
+ end
10
+
11
+ def puffer_navigation
12
+
13
+ end
14
+
15
+ def resource_session
16
+ postfix = params[:action] =~ /associated_/ ? params[:action] : ''
17
+ name = "#{current_resource.model_name}#{postfix}".to_sym
18
+ session[:resources] ||= {}
19
+ session[:resources][name] ||= {}
20
+ session[:resources][name][:boolean] ||= {}
21
+ session[:resources][name]
22
+ end
23
+
24
+ def searchable_fields fields
25
+ @searchable_fields ||= fields.map { |f| f if [:text, :string, :integer, :decimal, :float].include? f.type }.compact
26
+ end
27
+
28
+ def boolean_fields
29
+ @boolean_fields ||= index_fields.map { |f| f if ['boolean'].include? f.type.to_s }.compact
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,48 @@
1
+ module Puffer
2
+ module Controller
3
+ module Mutate
4
+
5
+ def self.included base
6
+ base.class_eval do
7
+ class_attribute :current_config
8
+ self.current_config = Puffer::Controller::Config.new
9
+
10
+ extend ClassMethods
11
+
12
+ layout 'puffer'
13
+
14
+ helper_method :current_resource, :current_config, :record, :records
15
+
16
+ rescue_from ActionView::MissingTemplate do |exception|
17
+ render current_resource.template(exception.path.split('/').last)
18
+ end
19
+ end
20
+ end
21
+
22
+ def current_resource
23
+ @current_resource ||= Puffer::Resource.new params, request
24
+ end
25
+
26
+ def record
27
+ @record || instance_variable_get("@#{current_resource.model_name}")
28
+ end
29
+
30
+ def records
31
+ @records || instance_variable_get("@#{current_resource.model_name.pluralize}")
32
+ end
33
+
34
+ module ClassMethods
35
+
36
+ def puffer?
37
+ true
38
+ end
39
+
40
+ def configure &block
41
+ block.bind(current_config).call
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ module Puffer
2
+ module Extensions
3
+ module ActiveRecord
4
+ module Base
5
+
6
+ def call_chain chain
7
+ swallow_nil{instance_eval(chain.to_s)}
8
+ end
9
+
10
+ def to_title
11
+ send title_column
12
+ end
13
+
14
+ def title_column
15
+ self.class.column_names[1].to_sym
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ ActiveRecord::Base.send :include, Puffer::Extensions::ActiveRecord::Base
@@ -0,0 +1,25 @@
1
+ module Puffer
2
+ module Extensions
3
+ module ActionController
4
+ module Base
5
+
6
+ def self.included base
7
+ base.class_eval do
8
+ extend ClassMethods
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ def puffer?
15
+ false
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ ActionController::Base.send :include, Puffer::Extensions::ActionController::Base
@@ -0,0 +1,36 @@
1
+ module Puffer
2
+ module Extensions
3
+
4
+ module String
5
+ def singular?
6
+ self.singularize == self
7
+ end
8
+
9
+ def plural?
10
+ self.pluralize == self
11
+ end
12
+ end
13
+
14
+ module Symbol
15
+ def singular?
16
+ to_s.singular?
17
+ end
18
+
19
+ def plural?
20
+ to_s.plural?
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+
27
+ String.send :include, Puffer::Extensions::String
28
+ Symbol.send :include, Puffer::Extensions::Symbol
29
+
30
+ Kernel.class_eval do
31
+ def swallow_nil
32
+ yield
33
+ rescue NoMethodError
34
+ nil
35
+ end
36
+ end
@@ -0,0 +1,125 @@
1
+ module Puffer
2
+ module Extensions
3
+ module Mapper
4
+
5
+ def self.included base
6
+ base.class_eval do
7
+ alias_method :original_resource, :resource
8
+ alias_method :original_resources, :resources
9
+
10
+ include InstanceMethods
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+
16
+ def resource *resources, &block
17
+ puffer_resource(*resources, &block) || original_resource(*resources, &block)
18
+ end
19
+
20
+ def resources *resources, &block
21
+ puffer_resources(*resources, &block) || original_resources(*resources, &block)
22
+ end
23
+
24
+ def puffer_resource(*resources, &block)
25
+ options = resources.extract_options!
26
+
27
+ if apply_common_behavior_for(:resource, resources, options, &block)
28
+ return self
29
+ end
30
+
31
+ resource = ActionDispatch::Routing::Mapper::Resources::SingletonResource.new(resources.pop, options)
32
+ controller = "#{[@scope[:module], resource.controller].compact.join("/")}_controller".classify.constantize rescue nil
33
+
34
+ return if controller.nil? || (controller && !controller.puffer?)
35
+
36
+ @scope[:ancestors] ||= []
37
+ @scope[:children] ||= []
38
+
39
+ resource_scope(resource) do
40
+ siblings = @scope[:children].dup
41
+ @scope[:children] = []
42
+ @scope[:ancestors].push resource.singular.to_sym
43
+
44
+ yield if block_given?
45
+
46
+ @scope[:ancestors].pop
47
+ options = {:plural => false, :ancestors => @scope[:ancestors].dup, :children => @scope[:children].dup}
48
+ siblings.push resource.singular.to_sym
49
+ @scope[:children] = siblings
50
+
51
+ collection do
52
+ post :create, options
53
+ end
54
+
55
+ new do
56
+ get :new, options
57
+ end
58
+
59
+ member do
60
+ get :edit, options
61
+ get :show, options
62
+ put :update, options
63
+ delete :destroy, options
64
+ end
65
+
66
+ end
67
+
68
+ self
69
+ end
70
+
71
+ def puffer_resources(*resources, &block)
72
+ options = resources.extract_options!
73
+
74
+ if apply_common_behavior_for(:resources, resources, options, &block)
75
+ return self
76
+ end
77
+
78
+ resource = ActionDispatch::Routing::Mapper::Resources::Resource.new(resources.pop, options)
79
+ controller = "#{[@scope[:module], resource.controller].compact.join("/")}_controller".classify.constantize rescue nil
80
+
81
+ return if controller.nil? || (controller && !controller.puffer?)
82
+
83
+ @scope[:ancestors] ||= []
84
+ @scope[:children] ||= []
85
+
86
+ resource_scope(resource) do
87
+ siblings = @scope[:children].dup
88
+ @scope[:children] = []
89
+ @scope[:ancestors].push resource.plural.to_sym
90
+
91
+ yield if block_given?
92
+
93
+ @scope[:ancestors].pop
94
+ options = {:plural => true, :ancestors => @scope[:ancestors].dup, :children => @scope[:children].dup}
95
+ siblings.push resource.plural.to_sym
96
+ @scope[:children] = siblings
97
+
98
+
99
+ collection do
100
+ get :index, options
101
+ post :create, options
102
+ end
103
+
104
+ new do
105
+ get :new, options
106
+ end
107
+
108
+ member do
109
+ get :edit, options
110
+ get :show, options
111
+ put :update, options
112
+ delete :destroy, options
113
+ end
114
+ end
115
+
116
+ self
117
+ end
118
+
119
+ end
120
+
121
+ end
122
+ end
123
+ end
124
+
125
+ ActionDispatch::Routing::Mapper.send :include, Puffer::Extensions::Mapper
@@ -0,0 +1,88 @@
1
+ module Puffer
2
+ class Field
3
+
4
+ attr_accessor :name, :options, :main_model
5
+
6
+ def initialize(model, name, options = {})
7
+ @main_model = model
8
+ @name = name
9
+ @options = options
10
+ end
11
+
12
+ def order
13
+ @order ||= options[:order] || query_column
14
+ end
15
+
16
+ def label
17
+ @label ||= options[:label] || @name.to_s.humanize
18
+ end
19
+
20
+ def [](key)
21
+ @options[key]
22
+ end
23
+
24
+ def to_s
25
+ @name.to_s
26
+ end
27
+
28
+ def own?
29
+ model == main_model
30
+ end
31
+
32
+ def toggable?
33
+ options[:toggable] = true if options[:toggable].nil?
34
+ own? && type == :boolean && options[:toggable]
35
+ end
36
+
37
+ def association
38
+ @association ||= main_model.reflect_on_association(to_s.split('.').first.to_sym)
39
+ end
40
+
41
+ def association?
42
+ !!association
43
+ end
44
+
45
+ def collection?
46
+ association? && [:has_many, :has_and_belongs_to_many].include?(association.macro)
47
+ end
48
+
49
+ def association_fields
50
+ @association_fields ||= @options[:fields].map {|sym| self.class.new(association.klass, sym) }
51
+ end
52
+
53
+ def association_key
54
+ association.primary_key_name
55
+ end
56
+
57
+ def record
58
+ name.split('.')[0..-2].join('.')
59
+ end
60
+
61
+ def model
62
+ unless @model
63
+ try_model = to_s.split('.')[-2]
64
+ @model = try_model.classify.constantize rescue nil if try_model
65
+ @model ||= main_model
66
+ end
67
+ @model
68
+ end
69
+
70
+ def type
71
+ @options[:type] = :association if association?
72
+ @options[:type].to_sym || swallow_nil{column.type}
73
+ end
74
+
75
+ def column
76
+ @column ||= model.columns.detect { |c| c.name == to_s.split('.').last}
77
+ end
78
+
79
+ def column?
80
+ !!column
81
+ end
82
+
83
+ def query_column
84
+ "#{model.to_s.tableize}.#{to_s.split('.').last}" if column
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,5 @@
1
+ module Puffer
2
+ class Railtie < Rails::Engine
3
+ config.autoload_paths << File.expand_path("../..", __FILE__)
4
+ end
5
+ end
@@ -0,0 +1,42 @@
1
+ module Puffer
2
+ class Resource
3
+ module Routing
4
+
5
+ include ActionController::UrlFor
6
+ include Rails.application.routes.url_helpers
7
+
8
+ def index_url *args
9
+ polymorphic_url *route_args(route_member(controller_name), *args)
10
+ end
11
+
12
+ def url *args
13
+ suggest = args.shift if args.first.is_a? ActiveRecord::Base
14
+ polymorphic_url *route_args(route_member(suggest), *args)
15
+ end
16
+
17
+ def new_url *args
18
+ new_polymorphic_url *route_args(controller_name.singularize, *args)
19
+ end
20
+
21
+ def edit_url *args
22
+ suggest = args.shift if args.first.is_a? ActiveRecord::Base
23
+ edit_polymorphic_url *route_args(route_member(suggest), *args)
24
+ end
25
+
26
+ def route_args *args
27
+ options = args.extract_options!
28
+ resource = args.shift
29
+ return args + [prefix] + ancestors.map(&:route_member) + [resource], options
30
+ end
31
+
32
+ def route_member suggest = nil
33
+ plural? ? (suggest || member) : controller_name.singularize
34
+ end
35
+
36
+ def default_url_options *args
37
+ Puffer::Base.default_url_options *args
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ module Puffer
2
+ class Resource
3
+ module Scoping
4
+
5
+
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,140 @@
1
+ module Puffer
2
+
3
+ ##############################################################
4
+ #
5
+ # Resource is presenter layer for controllers.
6
+ #
7
+ ##############################################################
8
+
9
+ class Resource
10
+
11
+ include Routing
12
+ include Scoping
13
+
14
+ attr_reader :request, :params, :prefix, :action, :controller_name, :model_name, :controller, :model
15
+
16
+ def initialize params, request = nil
17
+ @action = params.delete :action
18
+ @controller = "#{params[:controller]}_controller".classify.constantize
19
+ controller_segments = params.delete(:controller).split('/')
20
+ @prefix = controller_segments.first
21
+ @controller_name = controller_segments.last
22
+ @model_name = (controller.current_config.model || controller_name.singularize).to_s
23
+ @model = model_name.classify.constantize
24
+ @params = params
25
+ @request = request
26
+ end
27
+
28
+ def plural?
29
+ params[:plural]
30
+ end
31
+
32
+ def human_name
33
+ model_name.humanize
34
+ end
35
+
36
+ def parent
37
+ @parent ||= begin
38
+ parent_ancestors = params[:ancestors].dup
39
+ parent_name = parent_ancestors.pop
40
+ if parent_name
41
+ parent_params = ActiveSupport::HashWithIndifferentAccess.new({
42
+ :controller => "#{prefix}/#{parent_name.to_s.pluralize}",
43
+ :action => 'index',
44
+ :plural => parent_name.plural?,
45
+ :ancestors => parent_ancestors,
46
+ :children => []
47
+ })
48
+
49
+ parent_ancestors.each do |ancestor|
50
+ key = ancestor.to_s.singularize.foreign_key
51
+ parent_params.merge! key => params[key] if params[key]
52
+ end
53
+ parent_params.merge! :id => params[parent_name.to_s.singularize.foreign_key]
54
+
55
+ self.class.new parent_params, request
56
+ else
57
+ nil
58
+ end
59
+ end
60
+ end
61
+
62
+ def ancestors
63
+ @ancestors ||= begin
64
+ ancestors = []
65
+ resource = self
66
+ while resource = resource.parent do
67
+ ancestors.unshift resource
68
+ end
69
+ ancestors
70
+ end
71
+ end
72
+
73
+ def children(custom_params = {})
74
+ @children ||= params[:children].map do |child_name|
75
+ child_params = ActiveSupport::HashWithIndifferentAccess.new(custom_params.deep_merge({
76
+ :controller => "#{prefix}/#{child_name.to_s.pluralize}",
77
+ :action => 'index',
78
+ :plural => child_name.plural?,
79
+ :ancestors => params[:ancestors].dup.push((plural? ? controller_name : controller_name.singularize).to_sym),
80
+ :children => []
81
+ }))
82
+
83
+ params[:ancestors].each do |ancestor|
84
+ key = ancestor.to_s.singularize.foreign_key
85
+ child_params.merge! key => params[key] if params[key]
86
+ end
87
+ child_params.merge! controller_name.singularize.foreign_key => params[:id] if params[:id]
88
+
89
+ self.class.new child_params, request
90
+ end
91
+ end
92
+
93
+ def collection
94
+ scope = parent ? parent.member.send(model_name.pluralize) : model
95
+ scope.paginate :page => params[:page]
96
+ end
97
+
98
+ def member
99
+ if parent
100
+ if plural?
101
+ parent.member.send(model_name.pluralize).find params[:id]
102
+ else
103
+ parent.member.send(model_name)
104
+ end
105
+ else
106
+ model.find params[:id]
107
+ end
108
+ end
109
+
110
+ def new_member
111
+ if parent
112
+ if plural?
113
+ parent.member.send(model_name.pluralize).new attributes
114
+ else
115
+ parent.member.send("build_#{model_name}")
116
+ end
117
+ else
118
+ model.new attributes
119
+ end
120
+ end
121
+
122
+ def attributes
123
+ params[model_name] || {}
124
+ end
125
+
126
+ def template suggest = nil
127
+ "puffer/#{suggest || action}"
128
+ end
129
+
130
+ def method_missing method, *args, &block
131
+ method = method.to_s
132
+ if method.match(/path$/)
133
+ options = args.extract_options!
134
+ return send method.gsub(/path$/, 'url'), *(args << options.merge(:routing_type => :path))
135
+ end
136
+ model.send method, *args, &block
137
+ end
138
+
139
+ end
140
+ end
data/lib/puffer.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Puffer
2
+ end
3
+
4
+ require 'puffer/railtie'
5
+ require 'puffer/extensions/activerecord'
6
+ require 'puffer/extensions/controller'
7
+ require 'puffer/extensions/core'
8
+ require 'puffer/extensions/mapper'
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: puffer
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors: []
13
+
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-30 00:00:00 +03:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Insert Puffer description.
23
+ email:
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/puffer.rb
32
+ - lib/generators/puffer/controller/USAGE
33
+ - lib/generators/puffer/controller/controller_generator.rb
34
+ - lib/generators/puffer/controller/templates/controller.rb
35
+ - lib/generators/puffer/install/USAGE
36
+ - lib/generators/puffer/install/install_generator.rb
37
+ - lib/puffer/controller/config.rb
38
+ - lib/puffer/controller/helpers.rb
39
+ - lib/puffer/controller/mutate.rb
40
+ - lib/puffer/controller/dsl.rb
41
+ - lib/puffer/controller/actions.rb
42
+ - lib/puffer/field.rb
43
+ - lib/puffer/base.rb
44
+ - lib/puffer/extensions/mapper.rb
45
+ - lib/puffer/extensions/activerecord.rb
46
+ - lib/puffer/extensions/controller.rb
47
+ - lib/puffer/extensions/core.rb
48
+ - lib/puffer/resource.rb
49
+ - lib/puffer/railtie.rb
50
+ - lib/puffer/resource/scoping.rb
51
+ - lib/puffer/resource/routing.rb
52
+ - MIT-LICENSE
53
+ - Rakefile
54
+ - README.rdoc
55
+ has_rdoc: true
56
+ homepage:
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ requirements: []
83
+
84
+ rubyforge_project:
85
+ rubygems_version: 1.3.7
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Insert Puffer summary.
89
+ test_files: []
90
+