dry_crud 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (22) hide show
  1. data/README.rdoc +1 -5
  2. data/Rakefile +7 -15
  3. data/VERSION +1 -1
  4. data/lib/generators/dry_crud/templates/{public → app/assets}/images/actions/add.png +0 -0
  5. data/lib/generators/dry_crud/templates/{public → app/assets}/images/actions/delete.png +0 -0
  6. data/lib/generators/dry_crud/templates/{public → app/assets}/images/actions/edit.png +0 -0
  7. data/lib/generators/dry_crud/templates/{public → app/assets}/images/actions/list.png +0 -0
  8. data/lib/generators/dry_crud/templates/{public → app/assets}/images/actions/show.png +0 -0
  9. data/lib/generators/dry_crud/templates/{public → app/assets}/stylesheets/crud.css +0 -0
  10. data/lib/generators/dry_crud/templates/app/controllers/crud_controller.rb +12 -12
  11. data/lib/generators/dry_crud/templates/app/controllers/list_controller.rb +3 -5
  12. data/lib/generators/dry_crud/templates/app/helpers/standard_helper.rb +12 -13
  13. data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.erb +1 -1
  14. data/lib/generators/dry_crud/templates/test/crud_test_model.rb +4 -0
  15. data/lib/generators/dry_crud/templates/test/functional/crud_controller_test_helper.rb +13 -13
  16. data/test/templates/Gemfile +18 -16
  17. data/test/templates/app/controllers/cities_controller.rb +2 -2
  18. data/test/templates/app/views/ajax/ajax.js.erb +1 -0
  19. metadata +12 -14
  20. data/lib/generators/dry_crud/templates/app/controllers/render_inheritable.rb +0 -153
  21. data/lib/generators/dry_crud/templates/test/unit/helpers/render_inheritable_test.rb +0 -153
  22. data/test/templates/app/views/ajax/ajax.js.rjs +0 -1
data/README.rdoc CHANGED
@@ -19,7 +19,7 @@ To integrate DRY CRUD into your code, only a few additions are required:
19
19
  * For uniform CRUD functionality, just subclass your controllers from +CrudController+.
20
20
  * Overwrite the <tt>:to_s</tt> method of your models for a human-friendly representation in captions.
21
21
 
22
- Version 1.0 and higher are built for Rails 3. If you need a version for Rails 2.3, please get version 0.6.0 of the gem or go to the rails-2.3 branch on Github. DRY CRUD 1.3 is fully compatible with Ruby 1.8.7, Ruby 1.9.2 and JRuby.
22
+ Version 1.4 and higher are built for Rails 3.1. As of Rails 3.1, views are inheritable as well, so a core functionality of DRY CRUD got into the Rails core itself. For Rails 3.0, use version 1.3.1 or refer to the rails-3.0 branch. If you need a version for Rails 2.3, please get version 0.6.0 of the gem or go to the rails-2.3 branch on Github. DRY CRUD 1.3 is fully compatible with Ruby 1.8.7, Ruby 1.9.2 and JRuby.
23
23
 
24
24
  == Overview
25
25
 
@@ -31,8 +31,6 @@ Enter DRY CRUD.
31
31
  The main idea of DRY CRUD is to concentrate basic functionality of your application, like CRUD actions, uniform formatting, forms and tables into specifically extendable units. DRY CRUD generates various foundation classes that you may freely adapt to your application's needs. For each model, you may transparently customize arbitrary parts or just fallback to the general behavior. This applies not only for controllers, but also for view templates and helpers. There is no black box your code depends on. You lay the foundation that fits your application best.
32
32
  </b>
33
33
 
34
- A core element of DRY CRUD is the +RenderInheritable+ module. This gives you inheritable views and partials. In the default case, a template is searched in the current controller's view folder. If it is not found there, the template with the same name in the view folder of the superclass controller is used. This lookup path might be customized as well. RenderInheritable is also available as a stand-alone gem at http://github.com/codez/render_inheritable.
35
-
36
34
  DRY CRUD is a Rails generator. All code resides in your application and is open for you to inspect and to extend. You may pick whatever you consider useful or adapt what is not sufficient. Even if you do not require any CRUD functionality, you might find some helpers simplifying your work. There are no runtime dependencies to the dry_crud gem. Having said this, DRY CRUD does not want to provide a maximum of functionality that requires a lot of configuration, but rather a clean and lightweight foundation to build your application's requirements upon. This is why DRY CRUD comes as a generator and not as a Rails plugin.
37
35
 
38
36
  DRY CRUD does not depend on any other plugins, but easily allows you to integrate them in order to unify the behavior of your CRUD controllers. You might even use the plugins mentioned above to adapt your generated +CrudController+ base class. All classes come with thorough tests that provide you with a solid foundation for implementing your own adaptions.
@@ -219,8 +217,6 @@ All generated files are supposed to provide a reasonable foundation for the CRUD
219
217
 
220
218
  {controller/list_controller.rb}[http://codez.ch/dry_crud/?q=ListController]:: Abstract controller providing a basic list action. There are two sub-modules that provide search and sort functionality for the table displayed in the list action. A third sub-module remembers the list parameters in order to return to an identical list.
221
219
 
222
- {controller/render_inheritable.rb}[http://codez.ch/dry_crud/?q=RenderInheritable]:: A controller enhancement that allows one to render inheritable views and partials. If no view file is found for the current controller, the corresponding file is looked up in its superclass hierarchy. Thus, only views or partials that look differently have to be overwritten.
223
-
224
220
 
225
221
  === Helpers:
226
222
 
data/Rakefile CHANGED
@@ -1,13 +1,7 @@
1
1
  require 'rubygems'
2
- require "rake/testtask"
3
- require 'rake/gempackagetask'
4
- require 'rake/rdoctask'
5
- sdoc = begin
6
- require 'sdoc'
7
- true
8
- rescue Exception
9
- false
10
- end
2
+ require 'rake/testtask'
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
11
5
 
12
6
  load 'dry_crud.gemspec'
13
7
 
@@ -49,6 +43,8 @@ namespace :test do
49
43
  unless File.exist?(TEST_APP_ROOT)
50
44
  sh "rails new #{TEST_APP_ROOT}"
51
45
  FileUtils.cp(File.join(File.dirname(__FILE__), 'test', 'templates', 'Gemfile'), TEST_APP_ROOT)
46
+ sh "cd #{TEST_APP_ROOT}; bundle install" # update Gemfile.lock
47
+ FileUtils.rm_f(File.join(TEST_APP_ROOT, 'test', 'performance', 'browsing_test.rb'))
52
48
  end
53
49
  end
54
50
 
@@ -96,7 +92,7 @@ task :site => :rdoc do
96
92
  end
97
93
 
98
94
  # :package task
99
- Rake::GemPackageTask.new(DRY_CRUD_GEMSPEC) do |pkg|
95
+ Gem::PackageTask.new(DRY_CRUD_GEMSPEC) do |pkg|
100
96
  if Rake.application.top_level_tasks.include?('release')
101
97
  pkg.need_tar_gz = true
102
98
  pkg.need_tar_bz2 = true
@@ -107,11 +103,7 @@ end
107
103
  # :rdoc task
108
104
  Rake::RDocTask.new do |rdoc|
109
105
  rdoc.title = 'Dry Crud'
110
- rdoc.options << '--line-numbers' << '--inline-source'
111
- if sdoc
112
- rdoc.options << '--fmt' << 'shtml'
113
- rdoc.template = 'direct'
114
- end
106
+ rdoc.options << '--line-numbers'
115
107
  rdoc.rdoc_files.include(*FileList.new('*') do |list|
116
108
  list.exclude(/(^|[^.a-z])[a-z]+/)
117
109
  list.exclude('TODO')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.1
1
+ 1.4.0
@@ -1,6 +1,6 @@
1
1
  # Abstract controller providing basic CRUD actions.
2
2
  # This implementation mainly follows the one of the Rails scaffolding
3
- # controller and responses to HTML and XML requests. Some enhancements were made to ease extendability.
3
+ # controller and responses to HTML and JSON requests. Some enhancements were made to ease extendability.
4
4
  # Several protected helper methods are there to be (optionally) overriden by subclasses.
5
5
  # With the help of additional callbacks, it is possible to hook into the action procedures without
6
6
  # overriding the entire method.
@@ -31,14 +31,14 @@ class CrudController < ListController
31
31
 
32
32
  # Show one entry of this model.
33
33
  # GET /entries/1
34
- # GET /entries/1.xml
34
+ # GET /entries/1.json
35
35
  def show
36
36
  respond_with @entry
37
37
  end
38
38
 
39
39
  # Display a form to create a new entry of this model.
40
40
  # GET /entries/new
41
- # GET /entries/new.xml
41
+ # GET /entries/new.json
42
42
  def new
43
43
  @entry.attributes = params[model_identifier]
44
44
  respond_with @entry
@@ -49,7 +49,7 @@ class CrudController < ListController
49
49
  # To customize the response, you may overwrite this action and call
50
50
  # super with a block that gets success and format parameters.
51
51
  # POST /entries
52
- # POST /entries.xml
52
+ # POST /entries.json
53
53
  def create(&block)
54
54
  @entry.attributes = params[model_identifier]
55
55
  created = with_callbacks(:create, :save) { @entry.save }
@@ -57,10 +57,10 @@ class CrudController < ListController
57
57
  customizable_respond_to(created, block) do |format|
58
58
  if created
59
59
  format.html { redirect_to_show success_notice }
60
- format.xml { render :xml => @entry, :status => :created, :location => @entry }
60
+ format.json { render :json => @entry, :status => :created, :location => @entry }
61
61
  else
62
62
  format.html { render_with_callback 'new' }
63
- format.xml { render :xml => @entry.errors, :status => :unprocessable_entity }
63
+ format.json { render :json => @entry.errors, :status => :unprocessable_entity }
64
64
  end
65
65
  end
66
66
  end
@@ -76,7 +76,7 @@ class CrudController < ListController
76
76
  # To customize the response, you may overwrite this action and call
77
77
  # super with a block that gets success and format parameters.
78
78
  # PUT /entries/1
79
- # PUT /entries/1.xml
79
+ # PUT /entries/1.json
80
80
  def update(&block)
81
81
  @entry.attributes = params[model_identifier]
82
82
  updated = with_callbacks(:update, :save) { @entry.save }
@@ -84,10 +84,10 @@ class CrudController < ListController
84
84
  customizable_respond_to(updated, block) do |format|
85
85
  if updated
86
86
  format.html { redirect_to_show success_notice }
87
- format.xml { head :ok }
87
+ format.json { head :ok }
88
88
  else
89
89
  format.html { render_with_callback 'edit' }
90
- format.xml { render :xml => @entry.errors, :status => :unprocessable_entity }
90
+ format.json { render :json => @entry.errors, :status => :unprocessable_entity }
91
91
  end
92
92
  end
93
93
  end
@@ -97,20 +97,20 @@ class CrudController < ListController
97
97
  # To customize the response, you may overwrite this action and call
98
98
  # super with a block that gets success and format parameters.
99
99
  # DELETE /entries/1
100
- # DELETE /entries/1.xml
100
+ # DELETE /entries/1.json
101
101
  def destroy(&block)
102
102
  destroyed = run_callbacks(:destroy) { @entry.destroy }
103
103
 
104
104
  customizable_respond_to(destroyed, block) do |format|
105
105
  if destroyed
106
106
  format.html { redirect_to_index success_notice }
107
- format.xml { head :ok }
107
+ format.json { head :ok }
108
108
  else
109
109
  format.html {
110
110
  flash.alert = @entry.errors.full_messages.join('<br/>')
111
111
  request.env["HTTP_REFERER"].present? ? redirect_to(:back) : redirect_to_show
112
112
  }
113
- format.xml { render :xml => @entry.errors, :status => :unprocessable_entity }
113
+ format.json { render :json => @entry.errors, :status => :unprocessable_entity }
114
114
  end
115
115
  end
116
116
  end
@@ -6,8 +6,6 @@
6
6
  # the user the same list as he left it.
7
7
  class ListController < ApplicationController
8
8
 
9
- include RenderInheritable
10
-
11
9
  helper_method :model_class, :models_label
12
10
 
13
11
  delegate :model_class, :models_label, :to => 'self.class'
@@ -19,7 +17,7 @@ class ListController < ApplicationController
19
17
 
20
18
  # List all entries of this model.
21
19
  # GET /entries
22
- # GET /entries.xml
20
+ # GET /entries.json
23
21
  def index
24
22
  @entries = list_entries
25
23
  respond_with @entries
@@ -36,7 +34,7 @@ class ListController < ApplicationController
36
34
  def respond_with(object)
37
35
  respond_to do |format|
38
36
  format.html { render_with_callback action_name }
39
- format.xml { render :xml => object }
37
+ format.json { render :json => object }
40
38
  end
41
39
  end
42
40
 
@@ -135,7 +133,7 @@ class ListController < ApplicationController
135
133
  # Enhance the list entries with an optional sort order.
136
134
  def list_entries_with_sort
137
135
  if params[:sort].present? && sortable?(params[:sort])
138
- list_entries_without_sort.except(:order).order(sort_expression)
136
+ list_entries_without_sort.reorder(sort_expression)
139
137
  else
140
138
  list_entries_without_sort
141
139
  end
@@ -27,7 +27,7 @@ module StandardHelper
27
27
  # If the value is an associated model, renders the label of this object.
28
28
  # Otherwise, calls format_type.
29
29
  def format_attr(obj, attr)
30
- format_type_attr_method = :"format_#{obj.class.name.underscore}_#{attr.to_s}"
30
+ format_type_attr_method = obj.class.respond_to?(:model_name) ? :"format_#{obj.class.model_name.underscore}_#{attr.to_s}" : :"format_#{obj.class.name.underscore}_#{attr.to_s}"
31
31
  format_attr_method = :"format_#{attr.to_s}"
32
32
  if respond_to?(format_type_attr_method)
33
33
  send(format_type_attr_method, obj)
@@ -164,9 +164,8 @@ module StandardHelper
164
164
  html
165
165
  end
166
166
 
167
- # Translates the passed key by looking it up over the template lookup path
168
- # (i.e., usually the controller hierarchy). The key is searched in the following
169
- # order:
167
+ # Translates the passed key by looking it up over the controller hierarchy.
168
+ # The key is searched in the following order:
170
169
  # - {controller}.{current_partial}.{key}
171
170
  # - {controller}.{current_action}.{key}
172
171
  # - {controller}.global.{key}
@@ -177,16 +176,16 @@ module StandardHelper
177
176
  # - global.{key}
178
177
  def translate_inheritable(key, variables = {})
179
178
  defaults = []
180
- if controller.class.respond_to?(:template_lookup_path)
181
- partial = @_virtual_path ? @_virtual_path.gsub(%r{.*/_?}, "") : nil
182
- controller.class.template_lookup_path.each do |folder|
179
+ partial = @virtual_path ? @virtual_path.gsub(%r{.*/_?}, "") : nil
180
+ current = controller.class
181
+ while current < ActionController::Base
182
+ folder = current.controller_path
183
+ if folder.present?
183
184
  defaults << :"#{folder}.#{partial}.#{key}" if partial
184
185
  defaults << :"#{folder}.#{action_name}.#{key}"
185
186
  defaults << :"#{folder}.global.#{key}"
186
187
  end
187
- else
188
- defaults << :"#{controller_name}.#{action_name}.#{key}"
189
- defaults << :"#{controller_name}.global.#{key}"
188
+ current = current.superclass
190
189
  end
191
190
  defaults << :"global.#{key}"
192
191
 
@@ -205,9 +204,9 @@ module StandardHelper
205
204
  # - global.associations.{key}
206
205
  def translate_association(key, assoc = nil, variables = {})
207
206
  primary = if assoc
208
- variables[:default] ||= [:"activerecord.associations.#{assoc.klass.name.underscore}.#{key}",
207
+ variables[:default] ||= [:"activerecord.associations.#{assoc.klass.model_name.underscore}.#{key}",
209
208
  :"global.associations.#{key}"]
210
- :"activerecord.associations.models.#{assoc.active_record.name.underscore}.#{assoc.name}.#{key}"
209
+ :"activerecord.associations.models.#{assoc.active_record.model_name.underscore}.#{assoc.name}.#{key}"
211
210
  else
212
211
  :"global.associations.#{key}"
213
212
  end
@@ -261,7 +260,7 @@ module StandardHelper
261
260
 
262
261
  # Returns true if no link should be created when formatting the given association.
263
262
  def no_assoc_link?(assoc, val)
264
- !respond_to?("#{val.class.name.underscore}_path".to_sym)
263
+ !respond_to?("#{val.class.model_name.underscore}_path".to_sym)
265
264
  end
266
265
 
267
266
  # Returns the association proxy for the given attribute. The attr parameter
@@ -32,7 +32,7 @@
32
32
  </div>
33
33
  </div>
34
34
 
35
- <%= javascript_include_tag :defaults, :cache => 'all' %>
35
+ <%= javascript_include_tag 'application' %>
36
36
  <%= javascript_tag yield(:javascripts) if content_for?(:javascripts) %>
37
37
 
38
38
  </body>
@@ -130,6 +130,10 @@ module CrudTestHelper
130
130
  true
131
131
  end
132
132
 
133
+ def h(text)
134
+ ERB::Util.h(text)
135
+ end
136
+
133
137
  protected
134
138
 
135
139
  # Sets up the test database with a crud_test_models table.
@@ -11,11 +11,11 @@ module CrudControllerTestHelper
11
11
  assert_present assigns(:entries)
12
12
  end
13
13
 
14
- def test_index_xml
15
- get :index, :format => 'xml'
14
+ def test_index_json
15
+ get :index, :format => 'json'
16
16
  assert_response :success
17
17
  assert_present assigns(:entries)
18
- assert @response.body.starts_with?("<?xml")
18
+ assert @response.body.starts_with?("[{"), @response.body
19
19
  end
20
20
 
21
21
  def test_index_search
@@ -54,11 +54,11 @@ module CrudControllerTestHelper
54
54
  assert_equal test_entry, assigns(:entry)
55
55
  end
56
56
 
57
- def test_show_xml
58
- get :show, :id => test_entry.id, :format => 'xml'
57
+ def test_show_json
58
+ get :show, :id => test_entry.id, :format => 'json'
59
59
  assert_response :success
60
60
  assert_equal test_entry, assigns(:entry)
61
- assert @response.body.starts_with?("<?xml")
61
+ assert @response.body.starts_with?("{")
62
62
  end
63
63
 
64
64
  def test_show_with_not_existing_id_raises_RecordNotFound
@@ -89,12 +89,12 @@ module CrudControllerTestHelper
89
89
  assert_test_attrs_equal
90
90
  end
91
91
 
92
- def test_create_xml
92
+ def test_create_json
93
93
  assert_difference("#{model_class.name}.count") do
94
- post :create, model_identifier => test_entry_attrs, :format => 'xml'
94
+ post :create, model_identifier => test_entry_attrs, :format => 'json'
95
95
  end
96
96
  assert_response :success
97
- assert @response.body.starts_with?("<?xml")
97
+ assert @response.body.starts_with?("{")
98
98
  end
99
99
 
100
100
  def test_edit
@@ -118,9 +118,9 @@ module CrudControllerTestHelper
118
118
  assert_redirected_to assigns(:entry)
119
119
  end
120
120
 
121
- def test_update_xml
121
+ def test_update_json
122
122
  assert_no_difference("#{model_class.name}.count") do
123
- put :update, :id => test_entry.id, model_identifier => test_entry_attrs, :format => 'xml'
123
+ put :update, :id => test_entry.id, model_identifier => test_entry_attrs, :format => 'json'
124
124
  end
125
125
  assert_response :success
126
126
  assert_equal "", @response.body.strip
@@ -133,9 +133,9 @@ module CrudControllerTestHelper
133
133
  assert_redirected_to_index
134
134
  end
135
135
 
136
- def test_destroy_xml
136
+ def test_destroy_json
137
137
  assert_difference("#{model_class.name}.count", -1) do
138
- delete :destroy, :id => test_entry.id, :format => 'xml'
138
+ delete :destroy, :id => test_entry.id, :format => 'json'
139
139
  end
140
140
  assert_response :success
141
141
  assert_equal "", @response.body.strip
@@ -1,34 +1,36 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'rails'
3
+ gem 'rails', '>= 3.1'
4
4
 
5
5
  # Bundle edge Rails instead:
6
- # gem 'rails', :git => 'git://github.com/rails/rails.git'
6
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
7
 
8
8
  gem 'sqlite3', :platforms => :ruby
9
9
 
10
10
  gem 'jdbc-sqlite3', '3.6.14.2.056', :platforms => :jruby
11
11
  gem 'activerecord-jdbcsqlite3-adapter', :platforms => :jruby
12
12
 
13
+ gem 'json'
14
+
15
+ # Gems used only for assets and not required
16
+ # in production environments by default.
17
+ group :assets do
18
+ gem 'sass-rails', '~> 3.1.5.rc.2'
19
+ gem 'coffee-rails', '~> 3.1.1'
20
+ gem 'uglifier', '>= 1.0.3'
21
+ end
22
+
23
+ gem 'jquery-rails'
24
+
25
+ # To use ActiveModel has_secure_password
26
+ # gem 'bcrypt-ruby', '~> 3.0.0'
27
+
13
28
  # Use unicorn as the web server
14
29
  # gem 'unicorn'
15
30
 
16
31
  # Deploy with Capistrano
17
32
  # gem 'capistrano'
18
33
 
19
- # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
34
+ # To use debugger
20
35
  # gem 'ruby-debug'
21
36
  # gem 'ruby-debug19', :require => 'ruby-debug'
22
-
23
- # Bundle the extra gems:
24
- # gem 'bj'
25
- # gem 'nokogiri'
26
- # gem 'sqlite3-ruby', :require => 'sqlite3'
27
- # gem 'aws-s3', :require => 'aws/s3'
28
-
29
- # Bundle gems for the local environment. Make sure to
30
- # put test-only gems in this group so their generators
31
- # and rake tasks are available in development mode:
32
- # group :development, :test do
33
- # gem 'webrat'
34
- # end
@@ -2,8 +2,8 @@ class CitiesController < AjaxController
2
2
 
3
3
  def show
4
4
  respond_to do |format|
5
- format.html { redirect_to_index flash }
6
- format.xml { render :xml => @entry }
5
+ format.html { redirect_to_index flash.to_hash }
6
+ format.json { render :json => @entry }
7
7
  end
8
8
  end
9
9
 
@@ -0,0 +1 @@
1
+ $('#response').html("<%= escape_javascript(render 'hello') %>");
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry_crud
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 3
9
- - 1
10
- version: 1.3.1
8
+ - 4
9
+ - 0
10
+ version: 1.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Pascal Zumkehr
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-04-26 00:00:00 +02:00
18
+ date: 2011-12-05 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -47,9 +47,14 @@ extra_rdoc_files:
47
47
  - VERSION
48
48
  files:
49
49
  - lib/generators/dry_crud/dry_crud_generator.rb
50
+ - lib/generators/dry_crud/templates/app/assets/images/actions/add.png
51
+ - lib/generators/dry_crud/templates/app/assets/images/actions/delete.png
52
+ - lib/generators/dry_crud/templates/app/assets/images/actions/edit.png
53
+ - lib/generators/dry_crud/templates/app/assets/images/actions/list.png
54
+ - lib/generators/dry_crud/templates/app/assets/images/actions/show.png
55
+ - lib/generators/dry_crud/templates/app/assets/stylesheets/crud.css
50
56
  - lib/generators/dry_crud/templates/app/controllers/crud_controller.rb
51
57
  - lib/generators/dry_crud/templates/app/controllers/list_controller.rb
52
- - lib/generators/dry_crud/templates/app/controllers/render_inheritable.rb
53
58
  - lib/generators/dry_crud/templates/app/helpers/crud_helper.rb
54
59
  - lib/generators/dry_crud/templates/app/helpers/list_helper.rb
55
60
  - lib/generators/dry_crud/templates/app/helpers/standard_form_builder.rb
@@ -74,12 +79,6 @@ files:
74
79
  - lib/generators/dry_crud/templates/app/views/shared/_labeled.html.erb
75
80
  - lib/generators/dry_crud/templates/config/locales/en_crud.yml
76
81
  - lib/generators/dry_crud/templates/INSTALL
77
- - lib/generators/dry_crud/templates/public/images/actions/add.png
78
- - lib/generators/dry_crud/templates/public/images/actions/delete.png
79
- - lib/generators/dry_crud/templates/public/images/actions/edit.png
80
- - lib/generators/dry_crud/templates/public/images/actions/list.png
81
- - lib/generators/dry_crud/templates/public/images/actions/show.png
82
- - lib/generators/dry_crud/templates/public/stylesheets/crud.css
83
82
  - lib/generators/dry_crud/templates/test/crud_test_model.rb
84
83
  - lib/generators/dry_crud/templates/test/custom_assertions.rb
85
84
  - lib/generators/dry_crud/templates/test/functional/crud_controller_test_helper.rb
@@ -87,7 +86,6 @@ files:
87
86
  - lib/generators/dry_crud/templates/test/unit/custom_assertions_test.rb
88
87
  - lib/generators/dry_crud/templates/test/unit/helpers/crud_helper_test.rb
89
88
  - lib/generators/dry_crud/templates/test/unit/helpers/list_helper_test.rb
90
- - lib/generators/dry_crud/templates/test/unit/helpers/render_inheritable_test.rb
91
89
  - lib/generators/dry_crud/templates/test/unit/helpers/standard_form_builder_test.rb
92
90
  - lib/generators/dry_crud/templates/test/unit/helpers/standard_helper_test.rb
93
91
  - lib/generators/dry_crud/templates/test/unit/helpers/standard_table_builder_test.rb
@@ -101,7 +99,7 @@ files:
101
99
  - test/templates/app/models/person.rb
102
100
  - test/templates/app/views/ajax/_actions_index.html.erb
103
101
  - test/templates/app/views/ajax/_hello.html.erb
104
- - test/templates/app/views/ajax/ajax.js.rjs
102
+ - test/templates/app/views/ajax/ajax.js.erb
105
103
  - test/templates/app/views/cities/_form.html.erb
106
104
  - test/templates/app/views/cities/_hello.html.erb
107
105
  - test/templates/app/views/cities/_list.html.erb
@@ -1,153 +0,0 @@
1
- # Allows one to render inheritable views and partials.
2
- # If no view file is found for the current controller, the corresponding file
3
- # is looked up in its superclass hierarchy. This module must only be
4
- # included in the root controller of the desired lookup hierarchy.
5
- #
6
- # By default, this module only supports direct inheritance over one level. By overriding
7
- # the method lookup_path, you may define a custom lookup path. By providing an object
8
- # for the 'with' parameter, this path may even be dynamic.
9
- module RenderInheritable
10
-
11
- # Add inheritable_root_path method to including controller.
12
- def self.included(controller_class)
13
- controller_class.send(:extend, ClassMethods)
14
-
15
- controller_class.send(:class_variable_set, :@@inheritable_root_controller, controller_class)
16
- controller_class.cattr_reader :inheritable_root_controller
17
- end
18
-
19
- # Performs a lookup for the given filename and returns the most specific
20
- # folder that contains the file.
21
- def find_inheritable_template_folder(name, partial = false)
22
- self.class.find_inheritable_template_folder(view_context, name, partial, formats, template_lookup_param)
23
- end
24
-
25
- # Override this method to specify a dynamic parameter used in the lookup path.
26
- # For the default inheritance lookup, this parameter is not needed.
27
- def template_lookup_param
28
- nil
29
- end
30
-
31
- module ClassMethods
32
-
33
- # Performs a lookup for the given filename and returns the most specific
34
- # folder that contains the file.
35
- def find_inheritable_template_folder(view_context, name, partial, formats, param = nil)
36
- find_inheritable_template_folder_cached(view_context, name, partial, formats, param) do
37
- find_inheritable_artifact(param) do |folder|
38
- view_context.template_exists?(name, folder, partial)
39
- end
40
- end
41
- end
42
-
43
- # Performs a lookup for a controller and returns the name of the most specific one found.
44
- # This method is primarly usefull when given a 'param' argument that is used
45
- # in a custom #template_lookup_path. In this case, no controller class would need to
46
- # exist to render templates from corresponding view folders.
47
- def inheritable_controller(param = nil)
48
- descendants = inheritable_root_controller.descendants
49
- c = find_inheritable_artifact(param) do |folder|
50
- descendants.any? { |s| s.controller_path == folder }
51
- end
52
- c || inheritable_root_controller.controller_path
53
- end
54
-
55
- # Runs through the lookup path and yields each folder to the passed block.
56
- # If the block returns true, this folder is returned and no further lookup
57
- # happens. If no folder is found, the nil is returned.
58
- def find_inheritable_artifact(param = nil)
59
- template_lookup_path(param).each { |folder| return folder if yield(folder) }
60
- nil
61
- end
62
-
63
- # An array of controller names / folders, ordered from most specific to most general.
64
- # May be dynamic dependening on the passed 'param' argument.
65
- # You may override this method in an own controller to customize the lookup path.
66
- def template_lookup_path(param = nil)
67
- inheritance_lookup_path
68
- end
69
-
70
- # The inheritance path of controllers that is used as default lookup path.
71
- def inheritance_lookup_path
72
- path = [self]
73
- until path.last == inheritable_root_controller
74
- path << path.last.superclass
75
- end
76
- path.collect(&:controller_path)
77
- end
78
-
79
- # Override view context class to include the render inheritable modules.
80
- def view_context_class
81
- @view_context_class ||= begin
82
- Class.new(super) do
83
- include RenderInheritable::View
84
- end
85
- end
86
- end
87
-
88
- private
89
-
90
- # Performs a lookup for a template folder using the cache.
91
- def find_inheritable_template_folder_cached(view_context, name, partial, formats, param = nil)
92
- prefix = inheritable_cache_get(formats, name, partial, param)
93
- return prefix if prefix
94
-
95
- prefix = yield
96
-
97
- if prefix
98
- template = view_context.find_template_without_lookup(name, prefix, partial)
99
- inheritable_cache_set(template.formats, name, partial, param, prefix)
100
- end
101
- prefix
102
- end
103
-
104
- # A simple template lookup cache for each controller.
105
- def inheritable_cache #:nodoc:
106
- # do not store keys on each access, only return default structure
107
- @inheritable_cache ||= Hash.new do |h1, k1|
108
- Hash.new do |h2, k2|
109
- Hash.new do |h3, k3|
110
- Hash.new
111
- end
112
- end
113
- end
114
- end
115
-
116
- # Gets the prefix from the cache. Returns nil if it's not there yet.
117
- def inheritable_cache_get(formats, name, partial, param)
118
- prefixes = formats.collect { |format| inheritable_cache[format.to_sym][partial][name][param] }
119
- prefixes.compact!
120
- prefixes.empty? ? nil : prefixes.first
121
- end
122
-
123
- # Stores the found prefix in the cache.
124
- def inheritable_cache_set(formats, name, partial, param, prefix)
125
- formats.each do |format|
126
- # assign hash default values to respective key
127
- inheritable_cache[format.to_sym] = hf = inheritable_cache[format.to_sym]
128
- hf[partial] = hp = hf[partial]
129
- hp[name] = hn = hp[name]
130
- # finally store prefix in the deepest hash
131
- hn[param] = prefix
132
- end
133
- end
134
-
135
- end
136
-
137
- # Extend ActionView so templates are looked up on a find_template call.
138
- module View
139
- def self.included(base)
140
- base.send :alias_method_chain, :find_template, :lookup
141
- end
142
-
143
- # Perform a template lookup if the prefix corresponds to the current controller's path.
144
- def find_template_with_lookup(name, prefix = nil, partial = false)
145
- if prefix == controller_path
146
- folder = controller.find_inheritable_template_folder(name, partial)
147
- prefix = folder if folder
148
- end
149
- find_template_without_lookup(name, prefix, partial)
150
- end
151
- end
152
-
153
- end
@@ -1,153 +0,0 @@
1
- require 'test_helper'
2
-
3
- TEST_VIEW_PATH = File.join(Rails.root, 'test', 'test_views')
4
-
5
- class RootController < ApplicationController
6
- include RenderInheritable
7
-
8
- attr_accessor :default_template_format
9
-
10
- append_view_path(TEST_VIEW_PATH)
11
-
12
- def initialize(*args)
13
- super(*args)
14
- self.default_template_format = :html
15
- end
16
-
17
- def view_paths
18
- self.class.view_paths
19
- end
20
-
21
- end
22
-
23
- class ChildrenController < RootController
24
-
25
- end
26
-
27
- class GrandChildrenController < ChildrenController
28
-
29
- end
30
-
31
- # mock File object
32
- class File
33
- class << self
34
- def touched
35
- @touched ||= []
36
- end
37
-
38
- alias_method :orig_exists?, :exists?
39
- def exists?(filename, *args)
40
- touched.include?(filename) || orig_exists?(filename, *args)
41
- end
42
-
43
- def touch_template(file)
44
- touched << File.join(ActionController::Base.view_paths.first, "#{file}.html.erb")
45
- end
46
- end
47
- end
48
-
49
- class RenderInheritableTest < ActiveSupport::TestCase
50
-
51
- attr_reader :controller, :grand_controller
52
-
53
- def setup
54
- teardown
55
- @controller = ChildrenController.new
56
- @grand_controller = GrandChildrenController.new
57
- ChildrenController.send(:inheritable_cache).clear
58
- GrandChildrenController.send(:inheritable_cache).clear
59
- end
60
-
61
- def teardown
62
- FileUtils.rm_rf(TEST_VIEW_PATH)
63
- end
64
-
65
- test "inheritable_root_controller" do
66
- assert_equal RootController, RootController.inheritable_root_controller
67
- assert_equal RootController, ChildrenController.inheritable_root_controller
68
- assert_equal RootController, GrandChildrenController.inheritable_root_controller
69
- end
70
-
71
- test "lookup path" do
72
- assert_equal ['children', 'root'], ChildrenController.send(:inheritance_lookup_path)
73
- assert_equal ['grand_children', 'children', 'root'], GrandChildrenController.send(:inheritance_lookup_path)
74
- end
75
-
76
- test "inheritable controller finds controller instance" do
77
- assert_equal 'children', ChildrenController.send(:inheritable_controller)
78
- assert_equal 'grand_children', GrandChildrenController.send(:inheritable_controller)
79
- end
80
-
81
- test "find non-existing inheritable file" do
82
- assert_nil @controller.send(:find_inheritable_template_folder, 'foo')
83
- end
84
-
85
- test "find inheritable file not overwritten" do
86
- touch("root/root.html.erb")
87
-
88
- assert_equal 'root', @controller.send(:find_inheritable_template_folder, 'root')
89
- assert_equal 'root', @grand_controller.send(:find_inheritable_template_folder, 'root')
90
- end
91
-
92
- test "find inheritable file partially overwritten" do
93
- touch("root/child.html.erb")
94
- touch("children/child.html.erb")
95
-
96
- assert_equal 'children', @controller.send(:find_inheritable_template_folder, 'child')
97
- assert_equal 'children', @grand_controller.send(:find_inheritable_template_folder, 'child')
98
- end
99
-
100
- test "find inheritable file partially overwritten with gaps" do
101
- touch("root/grandchild.html.erb")
102
- touch("grand_children/grandchild.rhtml")
103
-
104
- assert_equal 'root', @controller.send(:find_inheritable_template_folder, 'grandchild')
105
- assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'grandchild')
106
- end
107
-
108
- test "find inheritable file for js format" do
109
- touch("root/_grandchild.js.rjs")
110
- touch("grand_children/_grandchild.js.rjs")
111
-
112
- assert_equal 'root', @controller.send(:find_inheritable_template_folder, 'grandchild', true)
113
- assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'grandchild', true)
114
-
115
- assert_equal({:js => { true => {'grandchild' => {nil => 'root'}}}}, ChildrenController.send(:inheritable_cache))
116
- assert_equal({:js => { true => {'grandchild' => {nil => 'grand_children'}}}}, GrandChildrenController.send(:inheritable_cache))
117
- end
118
-
119
- test "find inheritable file for xml format" do
120
- touch("root/_grandchild.xml.builder")
121
- touch("grand_children/_grandchild.xml.builder")
122
-
123
- assert_equal 'root', @controller.send(:find_inheritable_template_folder, 'grandchild', true)
124
- assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'grandchild', true)
125
- end
126
-
127
- test "find inheritable file all overwritten" do
128
- touch("root/all.html.erb")
129
- touch("children/all.rhtml")
130
- touch("grand_children/all.html.erb")
131
-
132
- assert_equal 'children', @controller.send(:find_inheritable_template_folder, 'all')
133
- assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'all')
134
-
135
- assert_equal({:html => { false => { 'all' => {nil => 'children'}}}}, ChildrenController.send(:inheritable_cache))
136
- assert_equal({:html => { false => { 'all' => {nil => 'grand_children'}}}}, GrandChildrenController.send(:inheritable_cache))
137
-
138
- assert_equal 'children', @controller.send(:find_inheritable_template_folder, 'all')
139
- assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'all')
140
-
141
- assert_equal({:html => { false => { 'all' => {nil => 'children'}}}}, ChildrenController.send(:inheritable_cache))
142
- assert_equal({:html => { false => { 'all' => {nil => 'grand_children'}}}}, GrandChildrenController.send(:inheritable_cache))
143
- end
144
-
145
- private
146
-
147
- def touch(file)
148
- f = File.join(TEST_VIEW_PATH, file)
149
- FileUtils.mkdir_p(File.dirname(f))
150
- FileUtils.touch(f)
151
- end
152
-
153
- end
@@ -1 +0,0 @@
1
- page.replace_html(:response, :partial => 'hello')