scaffolding_extensions 1.0.0

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 (52) hide show
  1. data/LICENSE +19 -0
  2. data/README +144 -0
  3. data/contrib/scaffold_associations_tree/README +9 -0
  4. data/contrib/scaffold_associations_tree/bullet.gif +0 -0
  5. data/contrib/scaffold_associations_tree/minus.gif +0 -0
  6. data/contrib/scaffold_associations_tree/plus.gif +0 -0
  7. data/contrib/scaffold_associations_tree/scaffold_associations_tree.css +20 -0
  8. data/contrib/scaffold_associations_tree/scaffold_associations_tree.js +57 -0
  9. data/contrib/scaffold_auto_complete_style/README +8 -0
  10. data/contrib/scaffold_auto_complete_style/auto_complete.css +23 -0
  11. data/contrib/scaffold_form_focus/README +12 -0
  12. data/contrib/scaffold_form_focus/scaffold_form_focus.js +21 -0
  13. data/contrib/scaffold_jquery_autocomplete/README +8 -0
  14. data/contrib/scaffold_jquery_autocomplete/jquery.ui.se_autocomplete.css +22 -0
  15. data/contrib/scaffold_jquery_autocomplete/jquery.ui.se_autocomplete.js +121 -0
  16. data/doc/advanced.txt +154 -0
  17. data/doc/camping.txt +25 -0
  18. data/doc/controller_spec.txt +20 -0
  19. data/doc/conversion.txt +102 -0
  20. data/doc/model_spec.txt +54 -0
  21. data/doc/ramaze.txt +20 -0
  22. data/doc/sinatra.txt +20 -0
  23. data/doc/testing.txt +12 -0
  24. data/lib/scaffolding_extensions.rb +89 -0
  25. data/lib/scaffolding_extensions/controller.rb +79 -0
  26. data/lib/scaffolding_extensions/controller/action_controller.rb +116 -0
  27. data/lib/scaffolding_extensions/controller/camping.rb +150 -0
  28. data/lib/scaffolding_extensions/controller/ramaze.rb +116 -0
  29. data/lib/scaffolding_extensions/controller/sinatra.rb +183 -0
  30. data/lib/scaffolding_extensions/helper.rb +304 -0
  31. data/lib/scaffolding_extensions/jquery_helper.rb +58 -0
  32. data/lib/scaffolding_extensions/meta_controller.rb +337 -0
  33. data/lib/scaffolding_extensions/meta_model.rb +571 -0
  34. data/lib/scaffolding_extensions/model.rb +30 -0
  35. data/lib/scaffolding_extensions/model/active_record.rb +184 -0
  36. data/lib/scaffolding_extensions/model/ardm.rb +47 -0
  37. data/lib/scaffolding_extensions/model/data_mapper.rb +190 -0
  38. data/lib/scaffolding_extensions/overridable.rb +67 -0
  39. data/lib/scaffolding_extensions/prototype_helper.rb +59 -0
  40. data/scaffolds/edit.rhtml +12 -0
  41. data/scaffolds/habtm.rhtml +24 -0
  42. data/scaffolds/index.rhtml +6 -0
  43. data/scaffolds/layout.rhtml +82 -0
  44. data/scaffolds/list.rhtml +13 -0
  45. data/scaffolds/listtable.rhtml +46 -0
  46. data/scaffolds/manage.rhtml +15 -0
  47. data/scaffolds/merge.rhtml +23 -0
  48. data/scaffolds/new.rhtml +5 -0
  49. data/scaffolds/search.rhtml +11 -0
  50. data/scaffolds/show.rhtml +19 -0
  51. data/test/scaffolding_extensions_test.rb +44 -0
  52. metadata +106 -0
@@ -0,0 +1,79 @@
1
+ module ScaffoldingExtensions
2
+ # This holds instance methods that are shared between controllers.
3
+ module Controller
4
+ private
5
+ # Respond "Method not allowed" if the action requested is nonidempotent and the method used isn't POST
6
+ def scaffold_check_nonidempotent_requests
7
+ scaffold_method_not_allowed if scaffolded_nonidempotent_method?(scaffold_request_action) && scaffold_request_method != 'POST'
8
+ end
9
+
10
+ # Force the given value into an array. If the items is currently an array,
11
+ # return it. If the item is nil or false, return the empty array. Otherwise,
12
+ # return an array with the value as the only member.
13
+ def scaffold_force_array(value)
14
+ if value
15
+ Array === value ? value : [value]
16
+ else
17
+ []
18
+ end
19
+ end
20
+
21
+ # Returns path to the given scaffold template file
22
+ def scaffold_path(template_name)
23
+ File.join(self.class.scaffold_template_dir, "#{template_name}.rhtml")
24
+ end
25
+
26
+ # Redirect to the appropriate form for the scaffolded model
27
+ #
28
+ # You can override this method on multiple levels. You can override a single
29
+ # action for all models via scaffold_#{action}_redirect (e.g.
30
+ # scaffold_edit_redirect or scaffold_new_redirect):
31
+ #
32
+ # def scaffold_#{action}_redirect(suffix, notice)
33
+ # # suffix is the suffix for the model, e.g. '_blog'
34
+ # # notice is a string with content suitable for the flash
35
+ # end
36
+ #
37
+ # You can override a single action for a single model via
38
+ # scaffold_#{action}#{suffix}_redirect (e.g. scaffold_edit_blog_redirect
39
+ # or scaffold_new_post_redirect):
40
+ #
41
+ # def scaffold_#{action}#{suffix}_redirect(notice)
42
+ # # notice is a string with content suitable for the flash
43
+ # end
44
+ #
45
+ # scaffold_#{action}#{suffix}_redirect has higher priority, and will be
46
+ # use even if scaffold_#{action}_redirect is defined, so you can override
47
+ # for the general case and override again for cases for specific models.
48
+ def scaffold_redirect(action, suffix, notice=nil, oid=nil)
49
+ action_suffix = "#{action}#{suffix}"
50
+ meth = "scaffold_#{action_suffix}_redirect"
51
+ return send(meth, notice) if respond_to?(meth)
52
+ meth = "scaffold_#{action}_redirect"
53
+ return send(meth, suffix, notice) if respond_to?(meth)
54
+ scaffold_flash[:notice] = notice if notice
55
+ scaffold_redirect_to(scaffold_url(action_suffix, oid ? {:id=>oid} : {}))
56
+ end
57
+
58
+ # Converts the value to an array, converts all values of the array to integers,
59
+ # removes all 0 values, and returns the array.
60
+ def scaffold_select_ids(value)
61
+ scaffold_force_array(value).collect{|x| x.to_i}.delete_if{|x| x == 0}
62
+ end
63
+
64
+ # Return whether scaffolding defined the method, whether or not it was overwritten
65
+ def scaffolded_method?(method_name)
66
+ self.class.scaffolded_methods.include?(method_name)
67
+ end
68
+
69
+ # Return whether scaffolding defined the method, if the method is nonidempotent
70
+ def scaffolded_nonidempotent_method?(method_name)
71
+ self.class.scaffolded_nonidempotent_methods.include?(method_name)
72
+ end
73
+
74
+ # Return true if the item was requested with XMLHttpRequest, false otherwise
75
+ def scaffold_xhr?
76
+ scaffold_request_env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/i
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,116 @@
1
+ module ScaffoldingExtensions
2
+ class << self
3
+ private
4
+ # ActionController::Base is generally used with Rails, which holds model files
5
+ # in app/models/
6
+ def model_files
7
+ @model_files ||= Dir["#{RAILS_ROOT}/app/models/*.rb"]
8
+ end
9
+ end
10
+
11
+ # Helper methods for ActionController::Base that override the defaults in Scaffolding Extensions
12
+ module ActionControllerHelper
13
+ private
14
+ # ActionController::Base requires that params that are desired to be lists have
15
+ # the suffix '[]'
16
+ def scaffold_param_list_suffix
17
+ '[]'
18
+ end
19
+
20
+ # ActionController::Base allows easy access to the CSRF token via token_tag
21
+ def scaffold_token_tag
22
+ token_tag
23
+ end
24
+ end
25
+
26
+ # Instance methods for ActionController::Base related necessary for Scaffolding Extensions
27
+ module ActionController
28
+ private
29
+ def scaffold_flash
30
+ flash
31
+ end
32
+
33
+ def scaffold_method_not_allowed
34
+ head(:method_not_allowed)
35
+ end
36
+
37
+ def scaffold_redirect_to(url)
38
+ redirect_to(url)
39
+ end
40
+
41
+ # Renders user provided template if it exists, otherwise renders a scaffold template.
42
+ # If a layout is specified (either in the controller or as an render_option), use that layout,
43
+ # otherwise uses the scaffolded layout. If :inline is one of the render_options,
44
+ # use the contents of it as the template without the layout.
45
+ def scaffold_render_template(action, options = {}, render_options = {})
46
+ suffix = options[:suffix]
47
+ suffix_action = "#{action}#{suffix}"
48
+ @scaffold_options ||= options
49
+ @scaffold_suffix ||= suffix
50
+ @scaffold_class ||= @scaffold_options[:class]
51
+ render_options = if template_exists?("#{self.class.controller_path}/#{suffix_action}")
52
+ {:action=>suffix_action}.merge(render_options)
53
+ elsif render_options.include?(:inline)
54
+ headers['Content-Type'] = 'text/javascript' if @scaffold_javascript
55
+ render_options.merge(:layout=>false)
56
+ else
57
+ if active_layout || render_options.include?(:layout)
58
+ {:file=>scaffold_path(action), :layout=>active_layout}.merge(render_options)
59
+ else
60
+ @content = render_to_string({:file=>scaffold_path(action)}.merge(render_options))
61
+ {:file=>scaffold_path("layout")}
62
+ end
63
+ end
64
+ render(render_options)
65
+ end
66
+
67
+ def scaffold_request_action
68
+ params[:action]
69
+ end
70
+
71
+ def scaffold_request_env
72
+ request.env
73
+ end
74
+
75
+ def scaffold_request_id
76
+ params[:id]
77
+ end
78
+
79
+ def scaffold_request_method
80
+ request.method.to_s.upcase
81
+ end
82
+
83
+ def scaffold_request_param(v)
84
+ params[v]
85
+ end
86
+
87
+ def scaffold_session
88
+ session
89
+ end
90
+
91
+ def scaffold_url(action, options = {})
92
+ url_for(options.merge(:action=>action, :only_path=>true))
93
+ end
94
+ end
95
+
96
+ # Class methods for ActionController::Base related necessary for Scaffolding Extensions
97
+ module MetaActionController
98
+ private
99
+ # Adds a before filter for checking nonidempotent requests use method POST
100
+ def scaffold_setup_helper
101
+ helper ScaffoldingExtensions::Helper
102
+ helper ScaffoldingExtensions::ActionControllerHelper
103
+ helper ScaffoldingExtensions::PrototypeHelper
104
+ include ScaffoldingExtensions::Controller
105
+ include ScaffoldingExtensions::ActionController
106
+ helper_method "scaffolded_method?", "scaffolded_nonidempotent_method?", :scaffold_url, :scaffold_flash, :scaffold_session
107
+ before_filter :scaffold_check_nonidempotent_requests
108
+ end
109
+ end
110
+ end
111
+
112
+ # Add class methods necessary for Scaffolding Extensions
113
+ class ActionController::Base
114
+ extend ScaffoldingExtensions::MetaController
115
+ extend ScaffoldingExtensions::MetaActionController
116
+ end
@@ -0,0 +1,150 @@
1
+ begin
2
+ require 'erubis'
3
+ ERB = Erubis::Eruby
4
+ rescue
5
+ require 'erb'
6
+ end
7
+ require 'cgi'
8
+
9
+ module ScaffoldingExtensions
10
+ class << self
11
+ private
12
+ # Camping doesn't have a default location for models, so assume none
13
+ def model_files
14
+ @model_files ||= []
15
+ end
16
+ end
17
+
18
+ module CampingHelper
19
+ private
20
+ # Camping doesn't include u
21
+ def u(s)
22
+ CGI.escape(s.to_s)
23
+ end
24
+
25
+ # Camping doesn't include h
26
+ def h(s)
27
+ CGI.escapeHTML(s.to_s)
28
+ end
29
+ end
30
+
31
+ # Instance methods for the Camping Controller related necessary for Scaffolding Extensions
32
+ module CampingController
33
+ private
34
+ # Camping doesn't provide a suitable flash. You can hack one together using
35
+ # session if you really need it.
36
+ def scaffold_flash
37
+ {}
38
+ end
39
+
40
+ # Not the most elegent approach, as this just raises an ArgumentError.
41
+ def scaffold_method_not_allowed
42
+ raise ArgumentError, 'Method Not Allowed'
43
+ end
44
+
45
+ # Seems as though redirect doesn't include the protocol, which is pretty weird,
46
+ # but it does work.
47
+ def scaffold_redirect_to(url)
48
+ redirect(url)
49
+ end
50
+
51
+ # In order to override the default templates, you need to set
52
+ # @scaffold_template_dir and then create a template file inside that
53
+ # to override the template (make sure the default templates are also
54
+ # in this folder). It doesn't support user modifiable layouts,
55
+ # so you'll have to modify the layout.rhtml file in @scaffold_template_dir.
56
+ def scaffold_render_template(action, options = {}, render_options = {})
57
+ suffix = options[:suffix]
58
+ suffix_action = "#{action}#{suffix}"
59
+ @scaffold_options ||= options
60
+ @scaffold_suffix ||= suffix
61
+ @scaffold_class ||= @scaffold_options[:class]
62
+ if render_options.include?(:inline)
63
+ headers = {}
64
+ headers['Content-Type'] = 'text/javascript' if @scaffold_javascript
65
+ r(200, ERB.new(render_options[:inline]).result(binding), headers)
66
+ else
67
+ @content = ERB.new(File.read(scaffold_path(File.exists?(scaffold_path(suffix_action)) ? suffix_action : action))).result(binding)
68
+ ERB.new(File.read(scaffold_path('layout'))).result(binding)
69
+ end
70
+ end
71
+
72
+ def scaffold_request_action
73
+ @scaffold_method
74
+ end
75
+
76
+ def scaffold_request_env
77
+ @env
78
+ end
79
+
80
+ def scaffold_request_id
81
+ @input[:id] || @scaffold_request_id
82
+ end
83
+
84
+ def scaffold_request_method
85
+ @scaffold_request_method
86
+ end
87
+
88
+ def scaffold_request_param(v)
89
+ @input[v]
90
+ end
91
+
92
+ # You need to enable Camping's session support for this to work,
93
+ # otherwise, this will always be the empty hash. The session data
94
+ # is only used for access control, so if you aren't using
95
+ # scaffold_session_value, it shouldn't matter.
96
+ def scaffold_session
97
+ @state || {}
98
+ end
99
+
100
+ # Treats the id option as special, appending it to the path.
101
+ # Uses the rest of the options as query string parameters.
102
+ def scaffold_url(action, options = {})
103
+ escaped_options = {}
104
+ options.each{|k,v| escaped_options[u(k.to_s)] = u(v.to_s)}
105
+ id = escaped_options.delete('id')
106
+ id = id ? "/#{id}" : ''
107
+ id << "?#{escaped_options.to_a.collect{|k,v| "#{k}=#{v}"}.join('&')}" unless escaped_options.empty?
108
+ "#{@scaffold_path}/#{action}#{id}"
109
+ end
110
+ end
111
+
112
+ # Class methods for the Camping Controller necessary for Scaffolding Extensions
113
+ module MetaCampingController
114
+ include ScaffoldingExtensions::MetaController
115
+ private
116
+ # Defines get and post methods for the controller that
117
+ # set necessary variables and then call the correct scaffold method
118
+ def scaffold_setup_helper
119
+ include ScaffoldingExtensions::Controller
120
+ include ScaffoldingExtensions::CampingController
121
+ include ScaffoldingExtensions::Helper
122
+ include ScaffoldingExtensions::PrototypeHelper
123
+ include ScaffoldingExtensions::CampingHelper
124
+ define_method(:get) do |path, meth, id|
125
+ @scaffold_request_method = 'GET'
126
+ @scaffold_path = path
127
+ @scaffold_method = meth.empty? ? 'index' : meth
128
+ @scaffold_request_id = id.empty? ? nil : id
129
+ scaffold_method_not_allowed if scaffolded_nonidempotent_method?(meth)
130
+ send(@scaffold_method)
131
+ end
132
+ define_method(:post) do |path, meth, id|
133
+ @scaffold_request_method = 'POST'
134
+ @scaffold_path = path
135
+ @scaffold_method = meth.empty? ? 'index' : meth
136
+ @scaffold_request_id = id.empty? ? nil : id
137
+ send(@scaffold_method)
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ # Create a route class, and automatically extend it with
144
+ # MetaCampingController so scaffold methods can be used directly
145
+ # inside of it.
146
+ def scaffold_R(root)
147
+ r = Camping::Controllers::R("(#{root})/?([^/]*)/?([^/]*)")
148
+ r.send(:extend, ScaffoldingExtensions::MetaCampingController)
149
+ r
150
+ end
@@ -0,0 +1,116 @@
1
+ module ScaffoldingExtensions
2
+ class << self
3
+ private
4
+ # Ramaze's default location for models is model/
5
+ def model_files
6
+ @model_files ||= Dir["model/*.rb"]
7
+ end
8
+ end
9
+
10
+ # Instance methods for Ramaze::Controller related necessary for Scaffolding Extensions
11
+ module RamazeController
12
+ private
13
+ def scaffold_flash
14
+ flash
15
+ end
16
+
17
+ def scaffold_method_not_allowed
18
+ respond('Method not allowed', 405)
19
+ end
20
+
21
+ def scaffold_redirect_to(url)
22
+ redirect(url)
23
+ end
24
+
25
+ # Renders user provided template if it exists, otherwise renders a scaffold template.
26
+ # If a layout is specified (either in the controller or as an render_option), use that layout,
27
+ # otherwise uses the scaffolded layout. If :inline is one of the render_options,
28
+ # use the contents of it as the template without the layout.
29
+ def scaffold_render_template(action, options = {}, render_options = {})
30
+ suffix = options[:suffix]
31
+ suffix_action = "#{action}#{suffix}"
32
+ @scaffold_options ||= options
33
+ @scaffold_suffix ||= suffix
34
+ @scaffold_class ||= @scaffold_options[:class]
35
+ unless ::Ramaze::Action.current.template
36
+ if render_options.include?(:inline)
37
+ response['Content-Type'] = 'text/javascript' if @scaffold_javascript
38
+ render_options[:inline]
39
+ else
40
+ ::Ramaze::Action.current.template = scaffold_path(action)
41
+ end
42
+ end
43
+ end
44
+
45
+ def scaffold_request_action
46
+ ::Ramaze::Action.current.name
47
+ end
48
+
49
+ def scaffold_request_env
50
+ request.env
51
+ end
52
+
53
+ def scaffold_request_id
54
+ request.params['id']
55
+ end
56
+
57
+ def scaffold_request_method
58
+ request.env['REQUEST_METHOD']
59
+ end
60
+
61
+ def scaffold_request_param(v)
62
+ request.params[v.to_s]
63
+ end
64
+
65
+ def scaffold_session
66
+ session
67
+ end
68
+
69
+ # Treats the id option as special (appending it so the list of options),
70
+ # which requires a lambda router.
71
+ def scaffold_url(action, options = {})
72
+ escaped_options = {}
73
+ options.each{|k,v| escaped_options[u(k.to_s)] = u(v.to_s)}
74
+ escaped_options['id'] ? Rs(action, escaped_options.delete('id'), escaped_options) : Rs(action, escaped_options)
75
+ end
76
+ end
77
+
78
+ # Class methods for Ramaze::Controller related necessary for Scaffolding Extensions
79
+ module MetaRamazeController
80
+ DENY_LAYOUT_RE = %r{\A(scaffold_auto_complete_for|associations|add|remove)_}
81
+
82
+ private
83
+ # Denies the layout to names that match DENY_LAYOUT_RE (the Ajax methods).
84
+ # Sets request.params['id'] if it was given as part of the request path.
85
+ # Checks nonidempotent requests require POST.
86
+ def scaffold_define_method(name, &block)
87
+ deny_layout(name) if DENY_LAYOUT_RE.match(name)
88
+ scaffolded_methods.add(name)
89
+ define_method(name) do |*args|
90
+ scaffold_check_nonidempotent_requests
91
+ request.params['id'] = args.shift if args.length > 0
92
+ instance_eval(&block)
93
+ end
94
+ end
95
+
96
+ # Adds a default scaffolded layout if none has been set. Activates the Erubis
97
+ # engine. Includes the necessary scaffolding helper and controller methods.
98
+ def scaffold_setup_helper
99
+ engine :Erubis
100
+ include ScaffoldingExtensions::Controller
101
+ include ScaffoldingExtensions::RamazeController
102
+ include ScaffoldingExtensions::Helper
103
+ include ScaffoldingExtensions::PrototypeHelper
104
+ unless trait[:layout][:all]
105
+ layout(:scaffold_layout)
106
+ define_method(:scaffold_layout){::Ramaze::Action.current.template = scaffold_path(:layout)}
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ # Add class methods necessary for Scaffolding Extensions
113
+ class Ramaze::Controller
114
+ extend ScaffoldingExtensions::MetaController
115
+ extend ScaffoldingExtensions::MetaRamazeController
116
+ end