puffer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+