amrita2 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/README +1 -1
  2. data/init.rb +1 -0
  3. data/lib/amrita2/rails_bridge.rb +92 -7
  4. data/lib/amrita2/template.rb +12 -127
  5. data/lib/amrita2/testsupport.rb +0 -25
  6. data/lib/amrita2/version.rb +1 -1
  7. data/sample/depot/app/controllers/admin_controller.rb +3 -1
  8. data/sample/depot/app/helpers/cart_helper.rb +8 -0
  9. data/sample/depot/app/helpers/price_helper.rb +7 -0
  10. data/sample/depot/config/environment.rb +0 -14
  11. data/sample/depot/config/environments/development.rb +2 -2
  12. data/sample/depot/db/schema.rb +27 -20
  13. data/sample/depot/test/functional/admin_controller_test.rb +63 -22
  14. data/sample/depot/test/functional/store_controller_test.rb +30 -18
  15. data/sample/depot/vendor/plugins/will_paginate/init.rb +4 -0
  16. data/sample/depot/vendor/plugins/will_paginate/lib/will_paginate.rb +61 -0
  17. data/sample/depot/vendor/plugins/will_paginate/lib/will_paginate/collection.rb +132 -0
  18. data/sample/depot/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb +80 -0
  19. data/sample/depot/vendor/plugins/will_paginate/lib/will_paginate/finder.rb +181 -0
  20. data/sample/depot/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb +206 -0
  21. data/sample/depot/vendor/plugins/will_paginate/test/array_pagination_test.rb +131 -0
  22. data/sample/depot/vendor/plugins/will_paginate/test/boot.rb +23 -0
  23. data/sample/depot/vendor/plugins/will_paginate/test/finder_test.rb +290 -0
  24. data/sample/depot/vendor/plugins/will_paginate/test/fixtures/admin.rb +3 -0
  25. data/sample/depot/vendor/plugins/will_paginate/test/fixtures/company.rb +9 -0
  26. data/sample/depot/vendor/plugins/will_paginate/test/fixtures/developer.rb +11 -0
  27. data/sample/depot/vendor/plugins/will_paginate/test/fixtures/project.rb +15 -0
  28. data/sample/depot/vendor/plugins/will_paginate/test/fixtures/reply.rb +5 -0
  29. data/sample/depot/vendor/plugins/will_paginate/test/fixtures/schema.rb +38 -0
  30. data/sample/depot/vendor/plugins/will_paginate/test/fixtures/topic.rb +4 -0
  31. data/sample/depot/vendor/plugins/will_paginate/test/fixtures/user.rb +2 -0
  32. data/sample/depot/vendor/plugins/will_paginate/test/helper.rb +25 -0
  33. data/sample/depot/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb +23 -0
  34. data/sample/depot/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb +67 -0
  35. data/sample/depot/vendor/plugins/will_paginate/test/lib/load_fixtures.rb +13 -0
  36. data/sample/depot/vendor/plugins/will_paginate/test/pagination_test.rb +240 -0
  37. data/sample/hello/test1.rb +23 -0
  38. data/sample/login_engine/config/environment.rb +18 -20
  39. data/sample/login_engine/config/environments/development.rb +2 -2
  40. data/sample/login_engine/db/schema.rb +24 -17
  41. data/sample/login_engine/lib/login_engine/authenticated_system.rb +18 -18
  42. data/sample/login_engine/test/functional/user_controller_test.rb +1 -0
  43. data/sample/ramaze/ramaise_amrita2.rb +156 -0
  44. data/specs/attribute.rb +11 -0
  45. data/specs/datatypes.rb +13 -0
  46. data/specs/sample.rb +1 -2
  47. data/specs/sanitize.rb +14 -0
  48. metadata +28 -7
  49. data/sample/depot/app/helpers/ar_form.rb +0 -169
  50. data/sample/depot/app/helpers/form_tag.rb +0 -24
  51. data/sample/depot/app/helpers/standard_form.rb +0 -73
  52. data/sample/depot/test/integration/dsl_user_stories_test.rb +0 -126
  53. data/sample/depot/test/integration/user_stories_test.rb +0 -70
@@ -0,0 +1,80 @@
1
+ require 'will_paginate'
2
+ require 'set'
3
+
4
+ unless Hash.instance_methods.include? 'except'
5
+ Hash.class_eval do
6
+ # Returns a new hash without the given keys.
7
+ def except(*keys)
8
+ rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
9
+ reject { |key,| rejected.include?(key) }
10
+ end
11
+
12
+ # Replaces the hash without only the given keys.
13
+ def except!(*keys)
14
+ replace(except(*keys))
15
+ end
16
+ end
17
+ end
18
+
19
+ unless Hash.instance_methods.include? 'slice'
20
+ Hash.class_eval do
21
+ # Returns a new hash with only the given keys.
22
+ def slice(*keys)
23
+ allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
24
+ reject { |key,| !allowed.include?(key) }
25
+ end
26
+
27
+ # Replaces the hash with only the given keys.
28
+ def slice!(*keys)
29
+ replace(slice(*keys))
30
+ end
31
+ end
32
+ end
33
+
34
+ unless Hash.instance_methods.include? 'rec_merge!'
35
+ Hash.class_eval do
36
+ # Same as Hash#merge!, but recursively merges sub-hashes
37
+ # (stolen from Haml)
38
+ def rec_merge!(other)
39
+ other.each do |key, other_value|
40
+ value = self[key]
41
+ if value.is_a?(Hash) and other_value.is_a?(Hash)
42
+ value.rec_merge! other_value
43
+ else
44
+ self[key] = other_value
45
+ end
46
+ end
47
+ self
48
+ end
49
+ end
50
+ end
51
+
52
+ require 'will_paginate/collection'
53
+
54
+ unless Array.instance_methods.include? 'paginate'
55
+ # http://www.desimcadam.com/archives/8
56
+ Array.class_eval do
57
+ def paginate(options_or_page = {}, per_page = nil)
58
+ if options_or_page.nil? or Fixnum === options_or_page
59
+ if defined? WillPaginate::Deprecation
60
+ WillPaginate::Deprecation.warn <<-DEPR
61
+ Array#paginate now conforms to the main, ActiveRecord::Base#paginate API. You should \
62
+ call it with a parameters hash (:page, :per_page). The old API (numbers as arguments) \
63
+ has been deprecated and is going to be unsupported in future versions of will_paginate.
64
+ DEPR
65
+ end
66
+ page = options_or_page
67
+ options = {}
68
+ else
69
+ options = options_or_page
70
+ page = options[:page]
71
+ raise ArgumentError, "wrong number of arguments (1 hash or 2 Fixnums expected)" if per_page
72
+ per_page = options[:per_page]
73
+ end
74
+
75
+ WillPaginate::Collection.create(page || 1, per_page || 30, options[:total_entries] || size) do |pager|
76
+ pager.replace self[pager.offset, pager.per_page].to_a
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,181 @@
1
+ require 'will_paginate/core_ext'
2
+
3
+ module WillPaginate
4
+ # A mixin for ActiveRecord::Base. Provides +per_page+ class method
5
+ # and makes +paginate+ finders possible with some method_missing magic.
6
+ #
7
+ # Find out more in WillPaginate::Finder::ClassMethods
8
+ #
9
+ module Finder
10
+ def self.included(base)
11
+ base.extend ClassMethods
12
+ class << base
13
+ alias_method_chain :method_missing, :paginate
14
+ define_method(:per_page) { 30 } unless respond_to?(:per_page)
15
+ end
16
+ end
17
+
18
+ # = Paginating finders for ActiveRecord models
19
+ #
20
+ # WillPaginate doesn't really add extra methods to your ActiveRecord models
21
+ # (except +per_page+ unless it's already available). It simply intercepts
22
+ # the calls to paginating finders such as +paginate+, +paginate_by_user_id+
23
+ # (and so on) and translates them to ordinary finders: +find+,
24
+ # +find_by_user_id+, etc. It does so with some +method_missing+ magic, but
25
+ # you don't need to care for that. You simply use paginating finders same
26
+ # way you used ordinary ones. You only need to specify what page do you want:
27
+ #
28
+ # @posts = Post.paginate :page => params[:page]
29
+ #
30
+ # In paginating finders, "all" is implicit. No sense in paginating a single
31
+ # record, right? So:
32
+ #
33
+ # Post.paginate => Post.find :all
34
+ # Post.paginate_all_by_something => Post.find_all_by_something
35
+ # Post.paginate_by_something => Post.find_all_by_something
36
+ #
37
+ # Don't forget to pass the +page+ parameter! Without it, paginating finders
38
+ # will raise an error.
39
+ #
40
+ # == Options for paginating finders
41
+ # * <tt>:page</tt> -- REQUIRED, but defaults to 1 if false or nil
42
+ # * <tt>:per_page</tt> -- defaults to <tt>CurrentModel.per_page</tt> (which is 30 if not overridden)
43
+ # * <tt>:total_entries</tt> -- use only if you manually count total entries
44
+ # * <tt>:count</tt> -- additional options that are passed on to +count+
45
+ #
46
+ module ClassMethods
47
+ # This methods wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string
48
+ # based on the params otherwise used by paginating finds: +page+ and +per_page+.
49
+ #
50
+ # Example:
51
+ #
52
+ # @developers = Developer.paginate_by_sql ['select * from developers where salary > ?', 80000],
53
+ # :page => params[:page], :per_page => 3
54
+ #
55
+ # A query for counting rows will automatically be generated if you don't
56
+ # supply <tt>:total_entries</tt>. If you experience problems with this
57
+ # generated SQL, you might want to perform the count manually in your
58
+ # application.
59
+ #
60
+ def paginate_by_sql(sql, options)
61
+ WillPaginate::Collection.create(*wp_parse_options!(options)) do |pager|
62
+ query = sanitize_sql(sql)
63
+ options.update :offset => pager.offset, :limit => pager.per_page
64
+
65
+ original_query = query.dup
66
+ add_limit! query, options
67
+ # perfom the find
68
+ pager.replace find_by_sql(query)
69
+
70
+ unless pager.total_entries
71
+ count_query = original_query.sub /\bORDER\s+BY\s+[\w`,\s]+$/mi, ''
72
+ count_query = "SELECT COUNT(*) FROM (#{count_query}) AS count_table"
73
+ # perform the count query
74
+ pager.total_entries = count_by_sql(count_query)
75
+ end
76
+ end
77
+ end
78
+
79
+ def respond_to?(method, include_priv = false)
80
+ case method.to_sym
81
+ when :paginate, :paginate_by_sql
82
+ true
83
+ else
84
+ super(method.to_s.sub(/^paginate/, 'find'), include_priv)
85
+ end
86
+ end
87
+
88
+ protected
89
+
90
+ def method_missing_with_paginate(method, *args, &block)
91
+ # did somebody tried to paginate? if not, let them be
92
+ unless method.to_s.index('paginate') == 0
93
+ return method_missing_without_paginate(method, *args, &block)
94
+ end
95
+
96
+ options = args.pop
97
+ page, per_page, total_entries = wp_parse_options!(options)
98
+ # an array of IDs may have been given:
99
+ total_entries ||= (Array === args.first and args.first.size)
100
+
101
+ # paginate finders are really just find_* with limit and offset
102
+ finder = method.to_s.sub /^paginate/, 'find'
103
+
104
+ # :all is implicit
105
+ if finder == 'find'
106
+ args.unshift(:all) if args.empty?
107
+ elsif finder.index('find_by_') == 0
108
+ finder.sub! /^find/, 'find_all'
109
+ end
110
+
111
+ WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
112
+ args << options.except(:count).merge(:offset => pager.offset, :limit => pager.per_page)
113
+ pager.replace send(finder, *args)
114
+
115
+ # magic counting for user convenience:
116
+ pager.total_entries = wp_count!(options, args, finder) unless pager.total_entries
117
+ end
118
+ end
119
+
120
+ def wp_count!(options, args, finder)
121
+ excludees = [:count, :order, :limit, :offset]
122
+ unless options[:select] and options[:select] =~ /^\s*DISTINCT/i
123
+ excludees << :select # only exclude the select param if it doesn't begin with DISTINCT
124
+ end
125
+ # count expects (almost) the same options as find
126
+ count_options = options.except *excludees
127
+
128
+ # merge the hash found in :count
129
+ # this allows you to specify :select, :order, or anything else just for the count query
130
+ count_options.update(options.delete(:count) || {}) if options.key? :count
131
+
132
+ # we may have to scope ...
133
+ counter = Proc.new { count(count_options) }
134
+
135
+ # we may be in a model or an association proxy!
136
+ klass = (@owner and @reflection) ? @reflection.klass : self
137
+
138
+ count = if finder =~ /^find_/ and klass.respond_to?(scoper = finder.sub(/^find_/, 'with_'))
139
+ # scope_out adds a 'with_finder' method which acts like with_scope, if it's present
140
+ # then execute the count with the scoping provided by the with_finder
141
+ send(scoper, &counter)
142
+ elsif conditions = wp_extract_finder_conditions(finder, args)
143
+ # extracted the conditions from calls like "paginate_by_foo_and_bar"
144
+ with_scope(:find => { :conditions => conditions }, &counter)
145
+ else
146
+ counter.call
147
+ end
148
+
149
+ count.respond_to?(:length) ? count.length : count
150
+ end
151
+
152
+ def wp_parse_options!(options)
153
+ raise ArgumentError, 'hash parameters expected' unless options.respond_to? :symbolize_keys!
154
+ options.symbolize_keys!
155
+ raise ArgumentError, ':page parameter required' unless options.key? :page
156
+
157
+ if options[:count] and options[:total_entries]
158
+ raise ArgumentError, ':count and :total_entries are mutually exclusive parameters'
159
+ end
160
+
161
+ page = options.delete(:page) || 1
162
+ per_page = options.delete(:per_page) || self.per_page
163
+ total = options.delete(:total_entries)
164
+ [page, per_page, total]
165
+ end
166
+
167
+ private
168
+
169
+ # thanks to active record for making us duplicate this code
170
+ def wp_extract_finder_conditions(finder, arguments)
171
+ return unless match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(finder.to_s)
172
+
173
+ attribute_names = extract_attribute_names_from_match(match)
174
+ unless all_attributes_exists?(attribute_names)
175
+ raise "I can't make sense of `#{finder}`. Try doing the count manually"
176
+ end
177
+ construct_attributes_from_arguments(attribute_names, arguments)
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,206 @@
1
+ require 'will_paginate/core_ext'
2
+
3
+ module WillPaginate
4
+ # = Will Paginate view helpers
5
+ #
6
+ # Currently there is only one view helper: +will_paginate+. It renders the
7
+ # pagination links for the given collection. The helper itself is lightweight
8
+ # and serves only as a wrapper around link renderer instantiation; the
9
+ # renderer then does all the hard work of generating the HTML.
10
+ #
11
+ # == Global options for helpers
12
+ #
13
+ # Options for pagination helpers are optional and get their default values from the
14
+ # WillPaginate::ViewHelpers.pagination_options hash. You can write to this hash to
15
+ # override default options on the global level:
16
+ #
17
+ # WillPaginate::ViewHelpers.pagination_options[:prev_label] = 'Previous page'
18
+ #
19
+ # By putting this into your environment.rb you can easily translate link texts to previous
20
+ # and next pages, as well as override some other defaults to your liking.
21
+ module ViewHelpers
22
+ # default options that can be overridden on the global level
23
+ @@pagination_options = {
24
+ :class => 'pagination',
25
+ :prev_label => '&laquo; Previous',
26
+ :next_label => 'Next &raquo;',
27
+ :inner_window => 4, # links around the current page
28
+ :outer_window => 1, # links around beginning and end
29
+ :separator => ' ', # single space is friendly to spiders and non-graphic browsers
30
+ :param_name => :page,
31
+ :params => nil,
32
+ :renderer => 'WillPaginate::LinkRenderer',
33
+ :page_links => true,
34
+ :container => true
35
+ }
36
+ mattr_reader :pagination_options
37
+
38
+ # Renders Digg/Flickr-style pagination for a WillPaginate::Collection
39
+ # object. Nil is returned if there is only one page in total; no point in
40
+ # rendering the pagination in that case...
41
+ #
42
+ # ==== Options
43
+ # * <tt>:class</tt> -- CSS class name for the generated DIV (default: "pagination")
44
+ # * <tt>:prev_label</tt> -- default: "« Previous"
45
+ # * <tt>:next_label</tt> -- default: "Next »"
46
+ # * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4)
47
+ # * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1)
48
+ # * <tt>:separator</tt> -- string separator for page HTML elements (default: single space)
49
+ # * <tt>:param_name</tt> -- parameter name for page number in URLs (default: <tt>:page</tt>)
50
+ # * <tt>:params</tt> -- additional parameters when generating pagination links
51
+ # (eg. <tt>:controller => "foo", :action => nil</tt>)
52
+ # * <tt>:renderer</tt> -- class name of the link renderer (default: WillPaginate::LinkRenderer)
53
+ # * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true)
54
+ # * <tt>:container</tt> -- toggles rendering of the DIV container for pagination links, set to
55
+ # false only when you are rendering your own pagination markup (default: true)
56
+ # * <tt>:id</tt> -- HTML ID for the container (default: nil). Pass +true+ to have the ID automatically
57
+ # generated from the class name of objects in collection: for example, paginating
58
+ # ArticleComment models would yield an ID of "article_comments_pagination".
59
+ #
60
+ # All options beside listed ones are passed as HTML attributes to the container
61
+ # element for pagination links (the DIV). For example:
62
+ #
63
+ # <%= will_paginate @posts, :id => 'wp_posts' %>
64
+ #
65
+ # ... will result in:
66
+ #
67
+ # <div class="pagination" id="wp_posts"> ... </div>
68
+ #
69
+ # ==== Using the helper without arguments
70
+ # If the helper is called without passing in the collection object, it will
71
+ # try to read from the instance variable inferred by the controller name.
72
+ # For example, calling +will_paginate+ while the current controller is
73
+ # PostsController will result in trying to read from the <tt>@posts</tt>
74
+ # variable. Example:
75
+ #
76
+ # <%= will_paginate :id => true %>
77
+ #
78
+ # ... will result in <tt>@post</tt> collection getting paginated:
79
+ #
80
+ # <div class="pagination" id="posts_pagination"> ... </div>
81
+ #
82
+ def will_paginate(collection = nil, options = {})
83
+ options, collection = collection, nil if collection.is_a? Hash
84
+ unless collection or !controller
85
+ collection_name = "@#{controller.controller_name}"
86
+ collection = instance_variable_get(collection_name)
87
+ raise ArgumentError, "The #{collection_name} variable appears to be empty. Did you " +
88
+ "forget to specify the collection object for will_paginate?" unless collection
89
+ end
90
+ # early exit if there is nothing to render
91
+ return nil unless collection.page_count > 1
92
+ options = options.symbolize_keys.reverse_merge WillPaginate::ViewHelpers.pagination_options
93
+ # create the renderer instance
94
+ renderer_class = options[:renderer].to_s.constantize
95
+ renderer = renderer_class.new collection, options, self
96
+ # render HTML for pagination
97
+ renderer.to_html
98
+ end
99
+ end
100
+
101
+ # This class does the heavy lifting of actually building the pagination
102
+ # links. It is used by +will_paginate+ helper internally, but avoid using it
103
+ # directly (for now) because its API is not set in stone yet.
104
+ class LinkRenderer
105
+
106
+ def initialize(collection, options, template)
107
+ @collection = collection
108
+ @options = options
109
+ @template = template
110
+ end
111
+
112
+ def to_html
113
+ links = @options[:page_links] ? windowed_paginator : []
114
+ # previous/next buttons
115
+ links.unshift page_link_or_span(@collection.previous_page, 'disabled', @options[:prev_label])
116
+ links.push page_link_or_span(@collection.next_page, 'disabled', @options[:next_label])
117
+
118
+ html = links.join(@options[:separator])
119
+ @options[:container] ? @template.content_tag(:div, html, html_attributes) : html
120
+ end
121
+
122
+ def html_attributes
123
+ return @html_attributes if @html_attributes
124
+ @html_attributes = @options.except *(WillPaginate::ViewHelpers.pagination_options.keys - [:class])
125
+ # pagination of Post models will have the ID of "posts_pagination"
126
+ if @options[:container] and @options[:id] === true
127
+ @html_attributes[:id] = @collection.first.class.name.underscore.pluralize + '_pagination'
128
+ end
129
+ @html_attributes
130
+ end
131
+
132
+ protected
133
+
134
+ def windowed_paginator
135
+ inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i
136
+ window_from = current_page - inner_window
137
+ window_to = current_page + inner_window
138
+
139
+ # adjust lower or upper limit if other is out of bounds
140
+ if window_to > total_pages
141
+ window_from -= window_to - total_pages
142
+ window_to = total_pages
143
+ elsif window_from < 1
144
+ window_to += 1 - window_from
145
+ window_from = 1
146
+ end
147
+
148
+ visible = (1..total_pages).to_a
149
+ left_gap = (2 + outer_window)...window_from
150
+ right_gap = (window_to + 1)...(total_pages - outer_window)
151
+ visible -= left_gap.to_a if left_gap.last - left_gap.first > 1
152
+ visible -= right_gap.to_a if right_gap.last - right_gap.first > 1
153
+
154
+ links, prev = [], 0
155
+
156
+ visible.each do |n|
157
+ unless n - prev > 1
158
+ prev = n
159
+ links << page_link_or_span(n)
160
+ else
161
+ # ellipsis represents the gap between windows
162
+ prev = n - 1
163
+ links << '...'
164
+ redo
165
+ end
166
+ end
167
+
168
+ links
169
+ end
170
+
171
+ def page_link_or_span(page, span_class = 'current', text = nil)
172
+ text ||= page.to_s
173
+ if page and page != current_page
174
+ @template.link_to text, url_options(page)
175
+ else
176
+ @template.content_tag :span, text, :class => span_class
177
+ end
178
+ end
179
+
180
+ def url_options(page)
181
+ options = { param_name => page }
182
+ # page links should preserve GET parameters
183
+ options = params.merge(options) if @template.request.get?
184
+ options.rec_merge!(@options[:params]) if @options[:params]
185
+ return options
186
+ end
187
+
188
+ private
189
+
190
+ def current_page
191
+ @collection.current_page
192
+ end
193
+
194
+ def total_pages
195
+ @collection.page_count
196
+ end
197
+
198
+ def param_name
199
+ @param_name ||= @options[:param_name].to_sym
200
+ end
201
+
202
+ def params
203
+ @params ||= @template.params.to_hash.symbolize_keys
204
+ end
205
+ end
206
+ end