puffer 0.0.29 → 0.0.30

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.
Files changed (85) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +56 -52
  3. data/README.md +51 -43
  4. data/VERSION +1 -1
  5. data/app/assets/javascripts/puffer/application.js +3 -1
  6. data/app/assets/stylesheets/puffer/application.css +2 -0
  7. data/app/assets/stylesheets/puffer/puffer.css +5 -9
  8. data/app/components/base_component.rb +0 -1
  9. data/app/components/boolean/index.html.erb +1 -1
  10. data/app/components/boolean_component.rb +1 -1
  11. data/app/components/references_many/index.html.erb +1 -0
  12. data/app/components/references_many_component.rb +8 -0
  13. data/app/components/references_one_component.rb +6 -1
  14. data/app/components/select/filter.html.erb +2 -0
  15. data/app/components/select/form.html.erb +1 -1
  16. data/app/components/select_component.rb +13 -2
  17. data/app/controllers/admin/puffer_users_controller.rb +5 -1
  18. data/app/controllers/admin/sessions_controller.rb +4 -1
  19. data/app/controllers/puffer/base.rb +1 -1
  20. data/app/controllers/puffer/sessions_base.rb +3 -0
  21. data/app/controllers/puffer/tree_base.rb +4 -4
  22. data/app/helpers/puffer_helper.rb +16 -15
  23. data/app/models/puffer/puffer_user.rb +11 -10
  24. data/app/models/puffer_user.rb +14 -2
  25. data/app/views/layouts/puffer.html.erb +16 -17
  26. data/app/views/layouts/puffer_base.html.erb +1 -2
  27. data/app/views/layouts/puffer_dashboard.html.erb +2 -2
  28. data/app/views/puffer/base/edit.html.erb +12 -3
  29. data/app/views/puffer/base/new.html.erb +12 -3
  30. data/app/views/puffer/dashboard_base/index.html.erb +5 -5
  31. data/lib/generators/puffer/component/component_generator.rb +0 -1
  32. data/lib/generators/puffer/controller/controller_generator.rb +1 -1
  33. data/lib/generators/puffer/controller/templates/controller.rb +8 -0
  34. data/lib/puffer.rb +77 -13
  35. data/lib/puffer/component.rb +14 -9
  36. data/lib/puffer/controller/auth.rb +41 -2
  37. data/lib/puffer/controller/config.rb +1 -1
  38. data/lib/puffer/controller/mutate.rb +15 -6
  39. data/lib/puffer/extensions/core.rb +4 -0
  40. data/lib/puffer/extensions/directive_processor.rb +36 -0
  41. data/lib/puffer/extensions/form.rb +1 -1
  42. data/lib/puffer/extensions/mapper.rb +74 -149
  43. data/lib/puffer/field.rb +2 -4
  44. data/lib/puffer/field_set.rb +3 -15
  45. data/lib/puffer/filters.rb +105 -0
  46. data/lib/puffer/orm_adapter/active_record.rb +33 -0
  47. data/lib/puffer/orm_adapter/base.rb +4 -0
  48. data/lib/puffer/orm_adapter/mongoid.rb +29 -0
  49. data/lib/puffer/resource.rb +63 -62
  50. data/lib/puffer/resource/node.rb +71 -0
  51. data/lib/puffer/resource/routing.rb +4 -4
  52. data/lib/puffer/resource/tree.rb +36 -0
  53. data/puffer.gemspec +28 -8
  54. data/spec/dummy/app/controllers/admin/posts_controller.rb +1 -1
  55. data/spec/dummy/app/controllers/admin/users_controller.rb +1 -0
  56. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  57. data/spec/dummy/app/controllers/orms/active_record_orm_primals_controller.rb +36 -0
  58. data/spec/dummy/app/controllers/orms/mongoid_orm_primals_controller.rb +42 -0
  59. data/spec/dummy/app/models/active_record_orm.rb +5 -0
  60. data/spec/dummy/app/models/active_record_orm/primal.rb +2 -0
  61. data/spec/dummy/app/models/{mongoid_test.rb → mongoid_orm.rb} +1 -1
  62. data/spec/dummy/app/models/mongoid_orm/primal.rb +46 -0
  63. data/spec/dummy/config/environments/development.rb +3 -0
  64. data/spec/dummy/config/routes.rb +2 -1
  65. data/spec/dummy/db/migrate/20110930183902_create_active_record_orm_primals.rb +17 -0
  66. data/spec/dummy/db/schema.rb +15 -1
  67. data/spec/fabricators/active_record_orm/primal.rb +13 -0
  68. data/spec/fabricators/mongoid_orm/primal.rb +12 -0
  69. data/spec/generators/puffer/component/component_generator_spec.rb +32 -0
  70. data/spec/generators/puffer/controller/controller_generator_spec.rb +31 -0
  71. data/spec/helpers/puffer_helper_spec.rb +62 -0
  72. data/spec/lib/filters_spec.rb +21 -0
  73. data/spec/lib/orm_adapter/active_record_spec.rb +33 -0
  74. data/spec/lib/orm_adapter/base_shared.rb +97 -0
  75. data/spec/lib/orm_adapter/mongoid_spec.rb +46 -0
  76. data/spec/lib/resource/routing_spec.rb +5 -5
  77. data/spec/lib/resource/tree_spec.rb +31 -0
  78. data/spec/lib/resource_spec.rb +36 -37
  79. data/spec/spec_helper.rb +3 -2
  80. metadata +71 -43
  81. data/app/views/puffer/base/_form.html.erb +0 -11
  82. data/lib/generators/puffer/component/templates/component_spec.rb +0 -19
  83. data/lib/puffer/resource/scoping.rb +0 -19
  84. data/spec/dummy/app/controllers/orms/mongoid_tests_controller.rb +0 -19
  85. data/spec/lib/params_spec.rb +0 -120
@@ -5,8 +5,13 @@ class ReferencesOneComponent < Puffer::Component::Base
5
5
  end
6
6
 
7
7
  def choose
8
- @records = field.reflection.klass.includes(field.children.includes).where(field.children.searches(params[:search])).page(params[:page])
8
+ #@records = field.reflection.klass.includes(field.children.includes).where(field.children.searches(params[:search])).page(params[:page])
9
+ @records = field.reflection.klass.to_adapter.filter(field.reflection.klass, field.children, :search => params[:puffer_search]).page(params[:page])
9
10
  render
10
11
  end
11
12
 
13
+ def filter
14
+
15
+ end
16
+
12
17
  end
@@ -0,0 +1,2 @@
1
+ <dt><%= opts[:form].label field.field_name %></dt>
2
+ <dd><%= opts[:form].select field.field_name, @options, :include_blank => true %></dd>
@@ -1,5 +1,5 @@
1
1
  <% content_for :input do %>
2
- <%= opts[:form].select field, @options, {:include_blank => field.options[:include_blank]}, field.input_options %>
2
+ <%= opts[:form].select field, @options, {:include_blank => field.options.key?(:include_blank) ? field.options[:include_blank] : true }, field.input_options %>
3
3
  <% end %>
4
4
 
5
5
  <%= render :file => 'base/form' %>
@@ -1,7 +1,19 @@
1
1
  class SelectComponent < BaseComponent
2
2
 
3
3
  def form
4
- @options = case field.options[:select]
4
+ @options = select_options
5
+ super
6
+ end
7
+
8
+ def filter
9
+ @options = select_options
10
+ render
11
+ end
12
+
13
+ private
14
+
15
+ def select_options
16
+ case field.options[:select]
5
17
  when Symbol then
6
18
  parent_controller.view_context.send field.options[:select]
7
19
  when Proc then
@@ -9,7 +21,6 @@ class SelectComponent < BaseComponent
9
21
  else
10
22
  field.options[:select]
11
23
  end
12
- super
13
24
  end
14
25
 
15
26
  end
@@ -1,3 +1,7 @@
1
- class Admin::PufferUsersController < Puffer::PufferUsersBase
1
+ require 'puffer_user'
2
2
 
3
+ if defined?(PufferUser)
4
+ class Admin::PufferUsersController < Puffer::PufferUsersBase
5
+
6
+ end
3
7
  end
@@ -1,3 +1,6 @@
1
+ # Implemented basic rails auth with custom PufferUser model.
2
+ # Admin::SessionsController could be redefined in application.
3
+ # See Puffer::SessionsBase docs for additional info.
1
4
  class Admin::SessionsController < Puffer::SessionsBase
2
5
 
3
6
  def new
@@ -5,7 +8,7 @@ class Admin::SessionsController < Puffer::SessionsBase
5
8
  end
6
9
 
7
10
  def create
8
- @record = PufferUser.find_by_email(params[:puffer_user][:email])
11
+ @record = PufferUser.to_adapter.find_first(:conditions => {:email => params[:puffer_user][:email]})
9
12
  if @record && @record.authenticate(params[:puffer_user][:password])
10
13
  session[:puffer_user_id] = @record.id
11
14
  redirect_to admin_root_url
@@ -12,7 +12,7 @@ module Puffer
12
12
  respond_to :html, :js
13
13
 
14
14
  def index
15
- @records = resource.collection
15
+ @records = resource.collection.page(params[:page])
16
16
  end
17
17
 
18
18
  def show
@@ -1,3 +1,6 @@
1
+ # Puffer::SessionsBase is a base class for any Admin::SessionsController
2
+ # implementation by default implemented basic auth through PufferUser.
3
+ # See Puffer::SessionsDeviseBase for alternative implementation example.
1
4
  class Puffer::SessionsBase < ApplicationController
2
5
  unloadable
3
6
  pufferize!
@@ -7,8 +7,8 @@ module Puffer
7
7
  define_fieldset :tree, :fallbacks => :index
8
8
 
9
9
  def index
10
- return super if params[:search]
11
- @records = resource.collection_scope.includes(resource.includes)
10
+ return super if puffer_filters.any?
11
+ @records = resource.collection_scope
12
12
  if session[:expanded].present?
13
13
  @records = @records.where(["depth in (0, 1) or parent_id in (#{session[:expanded].join(', ')})"]).arrange
14
14
  else
@@ -34,7 +34,7 @@ module Puffer
34
34
  session[:expanded] ||= []
35
35
  session[:expanded].push params[:id] if @parent
36
36
  session[:expanded].uniq!
37
- @records = @parent.self_and_descendants.where(:parent_id => [@parent.parent_id] + session[:expanded]).includes(resource.includes).arrange
37
+ @records = resource.model.to_adapter.filter(@parent.self_and_descendants.where(:parent_id => [@parent.parent_id] + session[:expanded]), tree_fields).arrange
38
38
  render 'toggle'
39
39
  end
40
40
 
@@ -42,7 +42,7 @@ module Puffer
42
42
  @parent = resource.member
43
43
  session[:expanded] ||= []
44
44
  session[:expanded].delete params[:id]
45
- @records = resource.collection_scope.where(:id => [@parent.id]).includes(resource.includes).arrange
45
+ @records = resource.model.to_adapter.filter(resource.collection_scope.where(:id => [@parent.id]), tree_fields).arrange
46
46
  render 'toggle'
47
47
  end
48
48
 
@@ -1,25 +1,26 @@
1
1
  module PufferHelper
2
2
 
3
- def puffer_namespaces
4
- Rails.application.routes.puffer.keys.each do |prefix|
5
- yield prefix.to_s.humanize, send("#{prefix}_root_path"), prefix == namespace
3
+ def puffer_scopes_navigation
4
+ Rails.application.routes.resources_tree.map(&:scope).uniq.each do |scope|
5
+ yield scope, send("#{scope}_root_path"), scope == puffer_namespace
6
6
  end
7
7
  end
8
8
 
9
- def puffer_navigation
10
- Rails.application.routes.puffer[namespace].values.map(&:first).each do |controller|
11
- title = controller.configuration.group.to_s.humanize
12
- path = polymorphic_url [namespace, controller.model]
13
- current = configuration.group && resource.root.controller.configuration.group == controller.configuration.group
14
- yield title, path, current
9
+ def puffer_groups_navigation namespace = puffer_namespace
10
+ Rails.application.routes.resources_tree.roots.select {|node| node.controller.model && node.scope == namespace}.uniq_by(&:group).each do |resource_node|
11
+ path = send("#{resource_node.url_string}_path")
12
+ current = resource.resource_node ? resource.root.resource_node.group == resource_node.group : false
13
+
14
+ yield resource_node.group, path, current
15
15
  end
16
16
  end
17
17
 
18
- def sidebar_puffer_navigation
19
- (Rails.application.routes.puffer[namespace][configuration.group] || []).each do |controller|
20
- title = controller.model.model_name.human
21
- path = polymorphic_url [namespace, controller.model]
22
- current = controller.controller_name == resource.root.controller_name
18
+ def puffer_resources_navigation namespace = puffer_namespace, group = configuration.group
19
+ Rails.application.routes.resources_tree.roots.select {|node| node.controller.model && node.scope == namespace && node.group == group}.each do |resource_node|
20
+ title = resource_node.controller.model.model_name.human
21
+ path = send("#{resource_node.url_string}_path")
22
+ current = resource.resource_node ? resource.root.resource_node == resource_node : false
23
+
23
24
  yield title, path, current
24
25
  end
25
26
  end
@@ -41,7 +42,7 @@ module PufferHelper
41
42
  res = record.call_chain(field.to_s)
42
43
  end
43
44
  unless field.native?
44
- url = edit_polymorphic_path [resource.namespace, record.call_chain(field.path)] rescue nil
45
+ url = edit_polymorphic_path [resource.scope, record.call_chain(field.path)] rescue nil
45
46
  res = link_to res, url if url
46
47
  end
47
48
  res
@@ -1,24 +1,25 @@
1
- class Puffer::PufferUser < ActiveRecord::Base
2
- self.abstract_class = true
1
+ module Puffer::PufferUser
2
+ extend ActiveSupport::Concern
3
+ include ActiveModel::SecurePassword
3
4
 
4
- attr_protected :password_digest
5
-
6
- has_secure_password
5
+ included do
6
+ attr_protected :password_digest
7
+ has_secure_password
7
8
 
8
- validates :email, :uniqueness => true, :presence => true
9
- validates :password, :presence => true, :length => {:minimum => 6}, :on => :create
9
+ validates :email, :uniqueness => true, :presence => true
10
+ validates :password, :presence => true, :length => { :minimum => 6 }, :on => :create
11
+ end
10
12
 
11
- def roles= value
13
+ def roles= value = []
12
14
  value = value.split(',').map(&:strip).map(&:presence) if value.is_a?(String)
13
15
  write_attribute(:roles, value.join(', '))
14
16
  end
15
17
 
16
18
  def roles_array
17
- roles.split(',').map(&:strip).map(&:presence)
19
+ roles.to_s.split(',').map(&:strip).map(&:presence)
18
20
  end
19
21
 
20
22
  def has_role? role
21
23
  roles_array.include?(role.to_s)
22
24
  end
23
-
24
25
  end
@@ -1,3 +1,15 @@
1
- class PufferUser < Puffer::PufferUser
1
+ if defined?(Mongoid::Document)
2
+ class PufferUser
3
+ include Mongoid::Document
2
4
 
3
- end
5
+ field :email, :type => String
6
+ field :password_digest, :type => String
7
+ field :roles, :type => String
8
+
9
+ include Puffer::PufferUser
10
+ end
11
+ elsif defined?(ActiveRecord::Base) && ActiveRecord::Base.connection.table_exists?('puffer_users')
12
+ class PufferUser < ActiveRecord::Base
13
+ include Puffer::PufferUser
14
+ end
15
+ end
@@ -1,12 +1,12 @@
1
1
  <% content_for :header do %>
2
2
  <ul class="namespaces">
3
- <% puffer_namespaces do |title, path, current| %>
4
- <li<%= raw(current ? ' class="selected"' : '') %>><%= link_to title, path %></li>
3
+ <% puffer_scopes_navigation do |title, path, current| %>
4
+ <li<%= raw(current ? ' class="selected"' : '') %>><%= link_to title.to_s.humanize, path %></li>
5
5
  <% end %>
6
6
  </ul>
7
7
  <ul class="navigation">
8
- <% puffer_navigation do |title, path, current| %>
9
- <li<%= raw(current ? ' class="selected"' : '') %>><%= link_to title, path %></li>
8
+ <% puffer_groups_navigation do |title, path, current| %>
9
+ <li<%= raw(current ? ' class="selected"' : '') %>><%= link_to title.to_s.humanize, path %></li>
10
10
  <% end %>
11
11
  </ul>
12
12
  <% end %>
@@ -15,8 +15,8 @@
15
15
  <div class="columns">
16
16
  <div class="column sidebar">
17
17
  <div class="padder">
18
- <ul class="navigation">
19
- <% sidebar_puffer_navigation do |title, path, current| %>
18
+ <ul class="navigation">
19
+ <% puffer_resources_navigation do |title, path, current| %>
20
20
  <li<%= raw(current ? ' class="selected"' : '') %>>
21
21
  <%= link_to title, path %>
22
22
  <% if current %>
@@ -34,19 +34,18 @@
34
34
  <% end %>
35
35
  </p>
36
36
  </dd>
37
- <dt>Search</dt>
38
- <dd>
39
- <%= form_tag resource.collection_path, {:method => :get} do %>
40
- <%= text_field_tag :search, params[:search] %>
41
- <%= submit_tag 'Search' %>
42
37
 
43
- <% if false %>
44
- <% if resource_session[:search].present? %>
45
- <%= link_to 'clear', resource.collection_path %>
46
- <% end %>
47
- <% end %>
38
+ <%= form_for puffer_filters, :url => resource.collection_path, :method => :get do |f| %>
39
+ <dt><%= f.label :puffer_search %></dt>
40
+ <dd><%= f.text_field :puffer_search %></dd>
41
+
42
+ <% index_fields.columns.each do |field| %>
43
+ <%= field.render controller, :filter, :form => f %>
48
44
  <% end %>
49
- </dd>
45
+
46
+ <dd><%= submit_tag 'Search', :name => nil %></dd>
47
+ <% end %>
48
+
50
49
  </dl>
51
50
  </div>
52
51
  <% end %>
@@ -6,8 +6,7 @@
6
6
  <%= csrf_meta_tag %>
7
7
  <%= stylesheet_link_tag "puffer/application" %>
8
8
  <%= javascript_include_tag "puffer/application" %>
9
- <%= yield :stylesheets %>
10
- <%= yield :javascripts %>
9
+ <%= yield :assets %>
11
10
  </head>
12
11
  <body>
13
12
  <div class="body">
@@ -1,7 +1,7 @@
1
1
  <% content_for :header do %>
2
2
  <ul class="namespaces">
3
- <% puffer_namespaces do |title, path, current| %>
4
- <li<%= raw(current ? ' class="selected"' : '') %>><%= link_to title, path %></li>
3
+ <% puffer_scopes_navigation do |title, path, current| %>
4
+ <li<%= raw(current ? ' class="selected"' : '') %>><%= link_to title.to_s.humanize, path %></li>
5
5
  <% end %>
6
6
  </ul>
7
7
  <% end %>
@@ -1,6 +1,15 @@
1
1
  <% @title = "Edit #{resource.human}" %>
2
2
  <h1><%= @title %></h1>
3
- <%= form_for record, :url => resource.member_path, :html => {:multipart => true} do |f| %>
4
- <%= render :partial => 'form', :locals => { :f => f, :action => 'edit' } %>
5
- <% end %>
3
+ <%= form_for record, :url => resource.member_path do |f| %>
4
+ <ul class="form">
5
+ <% update_fields.each do |field| -%>
6
+ <li><%= field.render controller, :update, :form => f, :record => f.object %></li>
7
+ <% end -%>
8
+ </ul>
6
9
 
10
+ <div class="buttons">
11
+ <%= f.submit t('puffer.save') %>
12
+ <%= f.submit t('puffer.save_and_exit') %>
13
+ <%= link_to 'cancel', (request.referer || resource.collectin_path) %>
14
+ </div>
15
+ <% end %>
@@ -1,6 +1,15 @@
1
1
  <% @title = "New #{resource.human}" %>
2
2
  <h1><%= @title %></h1>
3
- <%= form_for record, :url => resource.collection_path, :html => {:multipart => true} do |f| %>
4
- <%= render :partial => 'form', :locals => { :f => f, :action => 'new' } %>
5
- <% end %>
3
+ <%= form_for record, :url => resource.collection_path do |f| %>
4
+ <ul class="form">
5
+ <% create_fields.each do |field| -%>
6
+ <li><%= field.render controller, :create, :form => f, :record => f.object %></li>
7
+ <% end -%>
8
+ </ul>
6
9
 
10
+ <div class="buttons">
11
+ <%= f.submit t('puffer.save') %>
12
+ <%= f.submit t('puffer.save_and_exit') %>
13
+ <%= link_to 'cancel', (request.referer || resource.collectin_path) %>
14
+ </div>
15
+ <% end %>
@@ -1,13 +1,13 @@
1
- <% Rails.application.routes.puffer.each do |(namespace, groups)| %>
2
- <h2><%= namespace.to_s.humanize %></h2>
1
+ <% puffer_scopes_navigation do |scope| %>
2
+ <h2><%= scope.to_s.humanize %></h2>
3
3
  <ul class="navigation">
4
- <% groups.each do |(group, controllers)| %>
4
+ <% puffer_groups_navigation scope do |group| %>
5
5
  <li>
6
6
  <span><%= group.to_s.humanize %></span>
7
7
  <ul class="additional">
8
- <% controllers.each do |controller| %>
8
+ <% puffer_resources_navigation scope, group do |resource, url| %>
9
9
  <li>
10
- <%= link_to controller.model.model_name.human, polymorphic_url([namespace, controller.model]) %>
10
+ <%= link_to resource, url %>
11
11
  </li>
12
12
  <% end %>
13
13
  </ul>
@@ -5,7 +5,6 @@ class Puffer::ComponentGenerator < Rails::Generators::NamedBase
5
5
  @name = name.underscore
6
6
 
7
7
  template 'component.rb', "app/components/#{@name}_component.rb"
8
- template 'component_spec.rb', "spec/app/components/#{@name}_component_spec.rb"
9
8
  end
10
9
 
11
10
  def generate_views
@@ -15,7 +15,7 @@ private
15
15
  end
16
16
 
17
17
  def attributes
18
- @model_name.constantize.columns.map(&:name)
18
+ @model_name.constantize.to_adapter.column_names
19
19
  end
20
20
 
21
21
  end
@@ -6,13 +6,21 @@ class <%= controller_name %>Controller < Puffer::Base
6
6
 
7
7
  index do
8
8
  <% attributes.each do |attribute| -%>
9
+ <% if %w(_id id _type type created_at updated_at).include?(attribute.to_s) -%>
10
+ # field :<%= attribute %>
11
+ <% else -%>
9
12
  field :<%= attribute %>
13
+ <% end -%>
10
14
  <% end -%>
11
15
  end
12
16
 
13
17
  form do
14
18
  <% attributes.each do |attribute| -%>
19
+ <% if %w(_id id _type type created_at updated_at).include?(attribute.to_s) -%>
20
+ # field :<%= attribute %>
21
+ <% else -%>
15
22
  field :<%= attribute %>
23
+ <% end -%>
16
24
  <% end -%>
17
25
  end
18
26
 
@@ -11,11 +11,18 @@ require 'puffer/extensions/controller'
11
11
  require 'puffer/extensions/core'
12
12
  require 'puffer/extensions/mapper'
13
13
  require 'puffer/extensions/form'
14
+ require 'puffer/extensions/directive_processor'
14
15
  require 'puffer/extensions/engine'
15
16
  require 'puffer/engine'
16
17
 
17
18
  module Puffer
18
19
 
20
+ class PufferError < StandardError
21
+ end
22
+
23
+ class ComponentMissing < PufferError
24
+ end
25
+
19
26
  module Controller
20
27
  autoload :Action, 'puffer/controller/actions'
21
28
  autoload :MemberAction, 'puffer/controller/actions'
@@ -24,24 +31,81 @@ module Puffer
24
31
 
25
32
  module Component
26
33
  autoload :Base, 'puffer/component'
34
+ end
27
35
 
28
- mattr_accessor :_mappings
29
- self._mappings = {}
36
+ # Puffer has two types of mappings. If maps <tt>field.type</tt> to component
37
+ # class and also maps field attributes to <tt>field.type</tt>
38
+ mattr_accessor :_component_mappings
39
+ self._component_mappings = {}
40
+
41
+ # Maps <tt>field.type</tt> to component class
42
+ #
43
+ # ex:
44
+ #
45
+ # Puffer.map_component :ckeditor, :rich, :text, :to => CkeditorComponent
46
+ #
47
+ # this declaration maps even text fields to use <tt>CkeditorComponent</tt> for
48
+ # rendering
49
+ def self.map_component *args
50
+ to = args.extract_options![:to]
51
+ args.each { |type| _component_mappings[type.to_sym] = to }
52
+ end
53
+
54
+ def self.component_for field
55
+ type = field
56
+ type = field.type if field.respond_to? :type
57
+ (_component_mappings[type.to_sym] || "#{type}_component").to_s.camelize.constantize
58
+ rescue NameError
59
+ raise ComponentMissing, "Missing `#{type}` component for `#{field}` field. Please use Puffer.map_component binding or specify field type manually"
60
+ end
61
+
62
+ map_component :belongs_to, :has_one, :to => :ReferencesOneComponent
63
+ map_component :has_many, :has_and_belongs_to_many, :to => :ReferencesManyComponent
64
+ map_component :date, :time, :datetime, :date_time, :timestamp, :to => :DateTimeComponent
65
+ map_component :integer, :float, :decimal, :big_decimal, :to => :StringComponent
66
+ map_component :"mongoid/fields/serializable/object", :"bson/object_id", :symbol, :array, :hash, :set, :range, :to => :StringComponent
30
67
 
31
- def self.map_component *args
32
- to = args.extract_options![:to]
33
- args.each { |type| _mappings[type.to_sym] = to }
34
- end
35
68
 
36
- def self.component_for type
37
- (_mappings[type.to_sym] || "#{type}_component").to_s.camelize.constantize
69
+
70
+
71
+ mattr_accessor :_field_type_customs
72
+ self._field_type_customs = []
73
+
74
+
75
+ # Appends or prepends custom type.
76
+ #
77
+ # ex:
78
+ #
79
+ # Puffer.append_custom_field_type :paperclip do |field|
80
+ # field.model.respond_to?(:attachment_definitions)
81
+ # && field.model.attachment_definitions.key?(:field.field_name.to_sym)
82
+ # end
83
+ def self.prepend_custom_field_type custom_type, &block
84
+ _field_type_customs.shift [custom_type, block]
85
+ end
86
+
87
+ def self.append_custom_field_type custom_type, &block
88
+ _field_type_customs.push [custom_type, block]
89
+ end
90
+
91
+ def self.field_type_for field
92
+ custom_type = swallow_nil{_field_type_customs.detect {|(type, block)| block.call(field) }.first}
93
+ case custom_type
94
+ when Proc then
95
+ custom_type.call(field)
96
+ else
97
+ custom_type
38
98
  end
99
+ end
39
100
 
40
- map_component :belongs_to, :has_one, :to => :ReferencesOneComponent
41
- map_component :has_many, :has_and_belongs_to_many, :to => :ReferencesManyComponent
42
- map_component :date, :time, :datetime, :timestamp, :to => :DateTimeComponent
43
- map_component :integer, :decimal, :to => :StringComponent
44
- map_component :array, :decimal, :to => :StringComponent
101
+ append_custom_field_type :select do |field|
102
+ field.options.key? :select
103
+ end
104
+ append_custom_field_type :password do |field|
105
+ field.name =~ /password/
106
+ end
107
+ append_custom_field_type(proc {|type| type.reflection.macro}) do |field|
108
+ field.reflection
45
109
  end
46
110
 
47
111
  end