presenting 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 (89) hide show
  1. data/LICENSE +20 -0
  2. data/README +10 -0
  3. data/Rakefile +22 -0
  4. data/app/assets/javascript/grid.js +0 -0
  5. data/app/assets/javascript/search.js +13 -0
  6. data/app/assets/stylesheets/details-color.css +7 -0
  7. data/app/assets/stylesheets/details.css +10 -0
  8. data/app/assets/stylesheets/form.css +1 -0
  9. data/app/assets/stylesheets/grid-color.css +71 -0
  10. data/app/assets/stylesheets/grid.css +64 -0
  11. data/app/assets/stylesheets/search-color.css +16 -0
  12. data/app/assets/stylesheets/search.css +45 -0
  13. data/app/controllers/presentation/assets_controller.rb +42 -0
  14. data/app/views/presentations/_details.erb +11 -0
  15. data/app/views/presentations/_field_search.erb +14 -0
  16. data/app/views/presentations/_form.erb +20 -0
  17. data/app/views/presentations/_grid.erb +70 -0
  18. data/app/views/presentations/_search.erb +7 -0
  19. data/config/routes.rb +3 -0
  20. data/lib/presentation/base.rb +48 -0
  21. data/lib/presentation/details.rb +19 -0
  22. data/lib/presentation/field_search.rb +65 -0
  23. data/lib/presentation/form.rb +149 -0
  24. data/lib/presentation/grid.rb +160 -0
  25. data/lib/presentation/search.rb +9 -0
  26. data/lib/presenting/attribute.rb +51 -0
  27. data/lib/presenting/configurable.rb +10 -0
  28. data/lib/presenting/defaults.rb +10 -0
  29. data/lib/presenting/field_set.rb +26 -0
  30. data/lib/presenting/form_helpers.rb +51 -0
  31. data/lib/presenting/helpers.rb +110 -0
  32. data/lib/presenting/sanitize.rb +19 -0
  33. data/lib/presenting/search.rb +185 -0
  34. data/lib/presenting/sorting.rb +87 -0
  35. data/lib/presenting/view.rb +3 -0
  36. data/lib/presenting.rb +9 -0
  37. data/rails/init.rb +12 -0
  38. data/test/assets_test.rb +58 -0
  39. data/test/attribute_test.rb +61 -0
  40. data/test/configurable_test.rb +20 -0
  41. data/test/details_test.rb +68 -0
  42. data/test/field_search_test.rb +102 -0
  43. data/test/field_set_test.rb +46 -0
  44. data/test/form_test.rb +287 -0
  45. data/test/grid_test.rb +219 -0
  46. data/test/helpers_test.rb +72 -0
  47. data/test/presenting_test.rb +15 -0
  48. data/test/rails/app/controllers/application_controller.rb +15 -0
  49. data/test/rails/app/controllers/users_controller.rb +36 -0
  50. data/test/rails/app/helpers/application_helper.rb +3 -0
  51. data/test/rails/app/helpers/users_helper.rb +2 -0
  52. data/test/rails/app/models/user.rb +2 -0
  53. data/test/rails/app/views/layouts/application.html.erb +15 -0
  54. data/test/rails/app/views/users/index.html.erb +10 -0
  55. data/test/rails/app/views/users/new.html.erb +2 -0
  56. data/test/rails/app/views/users/show.html.erb +1 -0
  57. data/test/rails/config/boot.rb +109 -0
  58. data/test/rails/config/database.yml +17 -0
  59. data/test/rails/config/environment.rb +13 -0
  60. data/test/rails/config/environments/development.rb +17 -0
  61. data/test/rails/config/environments/production.rb +24 -0
  62. data/test/rails/config/environments/test.rb +22 -0
  63. data/test/rails/config/locales/en.yml +5 -0
  64. data/test/rails/config/routes.rb +5 -0
  65. data/test/rails/db/development.sqlite3 +0 -0
  66. data/test/rails/db/migrate/20090213085444_create_users.rb +13 -0
  67. data/test/rails/db/migrate/20090213085607_populate_users.rb +13 -0
  68. data/test/rails/db/schema.rb +23 -0
  69. data/test/rails/db/test.sqlite3 +0 -0
  70. data/test/rails/log/development.log +858 -0
  71. data/test/rails/public/404.html +30 -0
  72. data/test/rails/public/422.html +30 -0
  73. data/test/rails/public/500.html +33 -0
  74. data/test/rails/public/javascripts/application.js +2 -0
  75. data/test/rails/public/javascripts/jquery.livequery.min.js +11 -0
  76. data/test/rails/public/javascripts/prototype.js +4320 -0
  77. data/test/rails/script/console +3 -0
  78. data/test/rails/script/dbconsole +3 -0
  79. data/test/rails/script/destroy +3 -0
  80. data/test/rails/script/generate +3 -0
  81. data/test/rails/script/plugin +3 -0
  82. data/test/rails/script/runner +3 -0
  83. data/test/rails/script/server +3 -0
  84. data/test/sanitize_test.rb +15 -0
  85. data/test/search_conditions_test.rb +137 -0
  86. data/test/search_test.rb +30 -0
  87. data/test/sorting_test.rb +63 -0
  88. data/test/test_helper.rb +66 -0
  89. metadata +217 -0
@@ -0,0 +1,185 @@
1
+ module Presenting
2
+ class Search
3
+ include Presenting::Configurable
4
+
5
+ # I want to support three configuration formats:
6
+ #
7
+ # Search.new(:fields => [:first_name, :last_name, :email])
8
+ #
9
+ # Search.new(:fields => {
10
+ # 'first_name' => :equals,
11
+ # 'last_name' => :begins_with,
12
+ # 'email' => :not_null
13
+ # })
14
+ #
15
+ # Search.new(:fields => {
16
+ # 'fname' => {:sql => 'first_name', :pattern => :equals},
17
+ # 'lname' => {:sql => 'last_name', :pattern => :begins_with},
18
+ # 'email' => {:sql => 'email', :pattern => :not_null}
19
+ # })
20
+ def fields=(obj)
21
+ case obj
22
+ when Array
23
+ obj.each do |name| fields << name end
24
+
25
+ when Hash
26
+ obj.each do |k, v|
27
+ fields << {k => v}
28
+ end
29
+ end
30
+ end
31
+
32
+ def fields
33
+ @fields ||= FieldSet.new
34
+ end
35
+
36
+ def to_sql(params, type = :simple)
37
+ send("to_#{type}_sql", params) unless params.blank?
38
+ end
39
+
40
+ protected
41
+
42
+ # handles a simple search where a given term is matched against a number of fields, and can match any of them.
43
+ # this is usually presented to the user as a single "smart" search box.
44
+ def to_simple_sql(term)
45
+ sql = fields.map(&:fragment).join(' OR ')
46
+ binds = fields.collect{|f| f.bind(term)}.compact
47
+ [sql, binds].flatten.compact
48
+ end
49
+
50
+ # handles a search setup where a user may enter a search value for any field, and anything entered must match.
51
+ # this is usually presented to the user as a set of labeled search boxes.
52
+ #
53
+ # example field terms:
54
+ # field_terms = {
55
+ # 'first_name' => {:value => 'Bob'}
56
+ # 'last_name' => {:value => 'Smith'}
57
+ # }
58
+ #
59
+ def to_field_sql(field_terms)
60
+ searched_fields = fields.select{|f| field_terms[f.name] and not field_terms[f.name][:value].blank?}
61
+ unless searched_fields.empty?
62
+ sql = searched_fields.map(&:fragment).join(' AND ')
63
+ binds = searched_fields.collect{|f| f.bind(field_terms[f.name][:value])}
64
+
65
+ [sql, binds].flatten.compact
66
+ end
67
+ end
68
+
69
+ class FieldSet < Array
70
+ def <<(val)
71
+ if val.is_a? Hash
72
+ k, v = *val.to_a.first
73
+ opts = v.is_a?(Hash) ? v : {:pattern => v}
74
+ opts[:name] = k
75
+ else
76
+ opts = {:name => val}
77
+ end
78
+ super Field.new(opts)
79
+ end
80
+ end
81
+
82
+ # TODO: a field may require extra joins when it is searched on
83
+ # TODO: support more than just mysql (need access to a Connection for quoting and attribute conditions)
84
+ class Field
85
+ include Presenting::Configurable
86
+
87
+ # required (this is what appears in the parameter hash)
88
+ attr_reader :name
89
+ def name=(val)
90
+ @name = val.to_s
91
+ end
92
+
93
+ # sql field (default == name)
94
+ def sql
95
+ @sql ||= name
96
+ end
97
+ attr_writer :sql
98
+
99
+ # a shortcut for common operator/bind_pattern combos
100
+ def pattern=(val)
101
+ case val
102
+ when :equals
103
+ self.operator = '= ?'
104
+ self.bind_pattern = '?'
105
+ when :begins_with
106
+ self.operator = 'LIKE ?'
107
+ self.bind_pattern = '?%'
108
+ when :ends_with
109
+ self.operator = 'LIKE ?'
110
+ self.bind_pattern = '%?'
111
+ when :contains
112
+ self.operator = 'LIKE ?'
113
+ self.bind_pattern = '%?%'
114
+ when :null
115
+ self.operator = 'IS NULL'
116
+ when :not_null
117
+ self.operator = 'IS NOT NULL'
118
+ when :true
119
+ self.operator = '= ?'
120
+ self.bind_pattern = true
121
+ when :false
122
+ self.operator = '= ?'
123
+ self.bind_pattern = false
124
+ when :less_than
125
+ self.operator = '< ?'
126
+ when :less_than_or_equal_to, :not_greater_than
127
+ self.operator = '<= ?'
128
+ when :greater_than
129
+ self.operator = '> ?'
130
+ when :greater_than_or_equal_to, :not_less_than
131
+ self.operator = '>= ?'
132
+ end
133
+ end
134
+
135
+ # the format for comparison with :sql, with an optional bind for search terms
136
+ # '= ?', 'LIKE ?', 'IN (?)', etc.
137
+ def operator
138
+ @operator ||= '= ?'
139
+ end
140
+ attr_writer :operator
141
+
142
+ # formats the term BEFORE binding into the sql
143
+ # e.g. '?', '?%', etc.
144
+ def bind_pattern
145
+ @bind_pattern ||= '?'
146
+ end
147
+ attr_writer :bind_pattern
148
+
149
+ # composes the sql fragment
150
+ def fragment
151
+ "#{sql} #{operator}"
152
+ end
153
+
154
+ # prepares the bindable term
155
+ def bind(term)
156
+ return nil unless operator.include?('?')
157
+ return bind_pattern unless bind_pattern.is_a? String
158
+ bind_pattern == '?' ? typecast(term) : bind_pattern.sub('?', typecast(term).to_s)
159
+ end
160
+
161
+ # you can set a data type for the field, which will be used to convert
162
+ # parameter values. currently this is mostly useful for :time searches.
163
+ attr_accessor :type
164
+
165
+ protected
166
+
167
+ def typecast(val)
168
+ case type
169
+ when :date
170
+ val.is_a?(String) ?
171
+ (Time.zone ? Time.zone.parse(val) : Time.parse(val)).to_date :
172
+ val
173
+
174
+ when :time, :datetime
175
+ val.is_a?(String) ?
176
+ (Time.zone ? Time.zone.parse(val) : Time.parse(val)) :
177
+ val
178
+
179
+ else
180
+ val.to_s.strip
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,87 @@
1
+ module Presenting
2
+ class Sorting
3
+ include Presenting::Configurable
4
+
5
+ # I want to support two configuration formats:
6
+ #
7
+ # Sorting.new(:fields => [:first_name, :last_name, :email])
8
+ #
9
+ # Sorting.new(:fields => {
10
+ # 'name' => 'CONCAT(first_name, last_name)',
11
+ # 'email' => 'email_address'
12
+ # })
13
+ def fields=(obj)
14
+ case obj
15
+ when Array
16
+ obj.each do |name| fields << name end
17
+
18
+ when Hash
19
+ obj.each do |k, v|
20
+ fields << {k => v}
21
+ end
22
+ end
23
+ end
24
+
25
+ def fields
26
+ @fields ||= FieldSet.new
27
+ end
28
+
29
+ def to_sql(param)
30
+ fields.each do |field|
31
+ # search for and return the first known field
32
+ return "#{field.sql} #{desc_or_asc param[field.name]}" if param[field.name]
33
+ end unless param.blank?
34
+ # no known fields found
35
+ default
36
+ end
37
+
38
+ # The default sorting, if no known fields are found in the parameters.
39
+ # Default sorting is specified by name/direction, using an array.
40
+ #
41
+ # Example:
42
+ #
43
+ # @sorting.default = [:name, 'asc']
44
+ #
45
+ def default
46
+ @default ||= "#{fields.first.sql} ASC"
47
+ end
48
+ def default=(val)
49
+ @default = "#{fields.find{|f| f.name == val.first.to_s}.sql} #{desc_or_asc val.second}"
50
+ end
51
+
52
+ protected
53
+
54
+ def desc_or_asc(val)
55
+ val.to_s.downcase == 'desc' ? 'DESC' : 'ASC'
56
+ end
57
+
58
+ class FieldSet < Array
59
+ def <<(val)
60
+ if val.is_a? Hash
61
+ k, v = *val.to_a.first
62
+ opts = v.is_a?(Hash) ? v : {:sql => v}
63
+ opts[:name] = k
64
+ else
65
+ opts = {:name => val}
66
+ end
67
+ super Field.new(opts)
68
+ end
69
+ end
70
+
71
+ class Field
72
+ include Presenting::Configurable
73
+
74
+ # required (this is what appears in the parameter hash)
75
+ attr_reader :name
76
+ def name=(val)
77
+ @name = val.to_s
78
+ end
79
+
80
+ # sql field (default == name)
81
+ attr_writer :sql
82
+ def sql
83
+ @sql ||= self.name.to_s
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,3 @@
1
+ class Presenting::View < ActionView::Base
2
+ delegate :protect_against_forgery?, :form_authenticity_token, :to => :controller
3
+ end
data/lib/presenting.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Presenting
2
+ # prior to Rails 2.3, you need to call this manually from your config/routes.rb
3
+ def self.draw_routes(map)
4
+ map.namespace(:presentation) do |presentation|
5
+ presentation.stylesheet 'stylesheets/:id.css', :controller => 'assets', :action => 'stylesheet', :format => 'css'
6
+ presentation.javascript 'javascript/:id.js', :controller => 'assets', :action => 'javascript', :format => 'js'
7
+ end
8
+ end
9
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,12 @@
1
+ ActionView::Base.class_eval { include Presenting::Helpers }
2
+ ActionController::Base.const_set(:Search, Presenting::Search)
3
+ ActionController::Base.const_set(:Sorting, Presenting::Sorting)
4
+ ActionView::Helpers::FormBuilder.class_eval { include Presenting::FormHelpers }
5
+
6
+ if defined? Rails # because tests don't define the Rails module
7
+ if Rails.version.match(/^2\.2/)
8
+ ActionController::Base.view_paths << File.join(File.dirname(__FILE__), 'app', 'views')
9
+ ActiveSupport::Dependencies.load_paths << File.dirname(__FILE__) + '/app/controllers'
10
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/app/controllers/'
11
+ end
12
+ end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'action_controller/test_case'
3
+ require 'action_controller/integration'
4
+
5
+ class Presentation::AssetsControllerTest < ActionController::TestCase
6
+
7
+ def setup
8
+ ActionController::Base.perform_caching = false
9
+ end
10
+
11
+ # stylesheet
12
+
13
+ def test_stylesheet_routing_recognition
14
+ assert_recognizes({:controller => "presentation/assets", :action => "stylesheet", :id => "foo", :format => "css"}, "/presentation/stylesheets/foo.css")
15
+ end
16
+
17
+ def test_stylesheet_routing_generation
18
+ assert_generates "/presentation/stylesheets/foo.css", {:controller => "presentation/assets", :action => "stylesheet", :id => "foo", :format => "css"}
19
+ end
20
+
21
+ def test_named_stylesheet_routes
22
+ assert_equal "/presentation/stylesheets/foo.css", presentation_stylesheet_path("foo", :format => 'css')
23
+ end
24
+
25
+ def test_retrieving_a_named_stylesheet
26
+ get :stylesheet, :id => 'grid', :format => 'css'
27
+ assert_response :success
28
+ assert_equal @response.body, File.read(File.join(PLUGIN_ROOT, 'app', 'assets', 'stylesheets', 'grid.css'))
29
+ end
30
+
31
+ def test_retrieving_multiple_named_stylesheets
32
+ get :stylesheet, :id => 'grid,form', :format => 'css'
33
+ assert_response :success
34
+ assert @response.body.include?(File.read(File.join(PLUGIN_ROOT, 'app', 'assets', 'stylesheets', 'grid.css')))
35
+ assert @response.body.include?(File.read(File.join(PLUGIN_ROOT, 'app', 'assets', 'stylesheets', 'form.css')))
36
+ end
37
+
38
+ # javascript
39
+
40
+ def test_javascript_routing_recognition
41
+ assert_recognizes({:controller => "presentation/assets", :action => "javascript", :id => "foo", :format => "js"}, "/presentation/javascript/foo.js")
42
+ end
43
+
44
+ def test_javascript_routing_generation
45
+ assert_generates "/presentation/javascript/foo.js", {:controller => "presentation/assets", :action => "javascript", :id => "foo", :format => "js"}
46
+ end
47
+
48
+ def test_named_javascript_routes
49
+ assert_equal "/presentation/javascript/foo.js", presentation_javascript_path("foo", :format => 'js')
50
+ end
51
+
52
+ def test_retrieving_multiple_named_javascripts
53
+ get :javascript, :id => 'grid,search', :format => 'js'
54
+ assert_response :success
55
+ assert @response.body.include?(File.read(File.join(PLUGIN_ROOT, 'app', 'assets', 'javascript', 'grid.js')))
56
+ assert @response.body.include?(File.read(File.join(PLUGIN_ROOT, 'app', 'assets', 'javascript', 'search.js')))
57
+ end
58
+ end
@@ -0,0 +1,61 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class AttributeTest < Presenting::Test
4
+
5
+ def setup
6
+ @a = Presenting::Attribute.new
7
+ end
8
+
9
+ def test_assigning_a_symbol_name
10
+ @a.name = :foo
11
+ assert_equal "Foo", @a.name, "name is typecast to a string and titleized"
12
+ assert_equal :foo, @a.value, "value is assumed to be a symbol as well"
13
+ end
14
+
15
+ def test_assigning_a_string_name
16
+ @a.name = "foo"
17
+ assert_equal "foo", @a.name, "name remains a string"
18
+ assert_equal "foo", @a.value, "value is assumed to be a string"
19
+ end
20
+
21
+ def test_symbol_values
22
+ @a.value = :foo
23
+ assert_equal "bar", @a.value_from(stub('row', :foo => "bar")), "symbols are methods"
24
+ end
25
+
26
+ def test_string_values
27
+ @a.value = "foo"
28
+ assert_equal "foo", @a.value_from(stub('row', :foo => "bar")), "strings are constant"
29
+ end
30
+
31
+ def test_proc_values
32
+ @a.value = proc{|row| "hello"}
33
+ assert_equal "hello", @a.value_from(stub('row', :foo => "bar")), "procs are custom"
34
+ end
35
+
36
+ def test_that_value_from_does_not_sanitizes_itself
37
+ @a.value = '<span>hello</span>'
38
+ @a.sanitize = true
39
+ assert_equal '<span>hello</span>', @a.value_from(nil)
40
+ end
41
+
42
+ def test_hash_rows_with_symbol_values
43
+ @a.value = :foo
44
+ assert_equal 'bar', @a.value_from({:foo => 'bar'}), "symbols are hash keys"
45
+ end
46
+
47
+ def test_sanitize_is_default_true
48
+ assert @a.sanitize?
49
+ end
50
+
51
+ def test_assigning_a_symbol_id
52
+ @a.id = :foo
53
+ assert_equal 'foo', @a.id
54
+ end
55
+
56
+ def test_default_id_from_complex_name
57
+ @a.name = 'Hello, World!'
58
+ assert_equal 'hello_world', @a.id
59
+ end
60
+ end
61
+
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ConfigurableTest < Presenting::Test
4
+ class ConfigurableUser
5
+ include Presenting::Configurable
6
+ attr_accessor :first_name
7
+ attr_reader :name
8
+ end
9
+
10
+ def test_setting_first_name_with_initializer
11
+ user = ConfigurableUser.new(:first_name => "Bob")
12
+ assert_equal 'Bob', user.first_name
13
+ end
14
+
15
+ def test_setting_unsettable_attribute
16
+ assert_raises NoMethodError do
17
+ ConfigurableUser.new(:name => 'Bob Jenkins')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class DetailsTest < Presenting::Test
4
+ def setup
5
+ @d = Presentation::Details.new
6
+ end
7
+
8
+ def test_adding_a_field_by_name
9
+ @d.fields = ["foo"]
10
+ assert_equal "foo", @d.fields.first.name, "name is stringified"
11
+ assert_equal "foo", @d.fields.first.value, "value is assumed to be a method"
12
+ end
13
+
14
+ def test_adding_a_field_by_name_and_value
15
+ @d.fields = [{"foo" => :bar}]
16
+ assert_equal "foo", @d.fields.first.name, "key is name"
17
+ assert_equal :bar, @d.fields.first.value, "value is value"
18
+ end
19
+
20
+ def test_adding_a_field_by_name_and_options
21
+ @d.fields = [{"foo" => {:value => :bar}}]
22
+ assert_equal "foo", @d.fields.first.name, "key is name"
23
+ assert_equal :bar, @d.fields.first.value, "value is found and saved"
24
+ end
25
+ end
26
+
27
+ class DetailsRenderTest < Presentation::RenderTest
28
+ def setup
29
+ @presentation = Presentation::Details.new
30
+ @presentation.presentable = stub('user', :name => 'foo', :email => 'foo@example.com')
31
+ @presentation.controller = TestController.new
32
+ end
33
+
34
+ def test_rendering_a_title
35
+ @presentation.title = 'Hello World'
36
+
37
+ assert_select '.presentation-details h3', 'Hello World'
38
+ end
39
+
40
+ def test_rendering_an_attribute
41
+ @presentation.fields = [:email]
42
+
43
+ assert_select '.presentation-details' do
44
+ assert_select 'dl' do
45
+ assert_select 'dt', 'Email'
46
+ assert_select 'dd', 'foo@example.com'
47
+ end
48
+ end
49
+ end
50
+
51
+ def test_rendering_sanitized_data
52
+ @presentation.fields = [
53
+ {:email => {:sanitize => false}},
54
+ {:name => {:sanitize => true}}
55
+ ]
56
+ @presentation.presentable = stub('user', :name => '&', :email => '&')
57
+
58
+ assert_select '.presentation-details' do
59
+ assert_select 'dl' do
60
+ assert_select 'dt:nth-of-type(1)', 'Email'
61
+ assert_select 'dd:nth-of-type(1)', '&'
62
+
63
+ assert_select 'dt:nth-of-type(2)', 'Name'
64
+ assert_select 'dd:nth-of-type(2)', '&amp;'
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,102 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class FieldSearchTest < Presenting::Test
4
+ def setup
5
+ @s = Presentation::FieldSearch.new
6
+ end
7
+
8
+ def test_adding_a_field_by_name
9
+ @s.fields = [:foo]
10
+ assert_equal "Foo", @s.fields.first.name
11
+ assert_equal :text, @s.fields.first.type
12
+ end
13
+
14
+ def test_adding_a_field_by_name_and_type
15
+ @s.fields = [{"foo" => :bar}]
16
+ assert_equal "foo", @s.fields.first.name
17
+ assert_equal :bar, @s.fields.first.type
18
+ end
19
+
20
+ def test_adding_a_field_by_name_and_options
21
+ @s.fields = [{"foo" => {:type => :bar}}]
22
+ assert_equal "foo", @s.fields.first.name
23
+ assert_equal :bar, @s.fields.first.type
24
+ end
25
+ end
26
+
27
+ class FieldSearchFieldTest < Presenting::Test
28
+ def setup
29
+ @f = Presentation::FieldSearch::Field.new
30
+ end
31
+
32
+ def test_assigning_a_symbol_name
33
+ @f.name = :foo
34
+ assert_equal "Foo", @f.name, "name is typecast to a string and titleized"
35
+ end
36
+
37
+ def test_assigning_a_string_name
38
+ @f.name = "foo"
39
+ assert_equal "foo", @f.name, "name remains a string"
40
+ end
41
+
42
+ def test_default_type
43
+ assert_equal :text, @f.type
44
+ end
45
+ end
46
+
47
+ class FieldSearchRenderingTest < Presentation::RenderTest
48
+ def setup
49
+ @presentation = Presentation::FieldSearch.new
50
+ @presentation.controller = TestController.new
51
+ @presentation.controller.request.path = '/users'
52
+ end
53
+
54
+ def test_rendering_a_form_reuses_current_path
55
+ assert_select 'form[action=/users?][method=get]'
56
+ end
57
+
58
+ def test_rendering_a_text_field
59
+ @presentation.fields << {:foo => :text}
60
+ assert_select "form input[type=text][name='search[foo][value]']"
61
+ end
62
+
63
+ def test_rendering_a_text_field_with_existing_value
64
+ @presentation.fields << {:foo => :text}
65
+ @presentation.controller.params[:search] = {'foo' => {:value => 'bar'}}
66
+ assert_select "form input[type=text][name='search[foo][value]'][value=bar]"
67
+ end
68
+
69
+ def test_rendering_a_checkbox_field
70
+ @presentation.fields << {:foo => :checkbox}
71
+ assert_select "form input[type=checkbox][name='search[foo][value]'][value=1]"
72
+ end
73
+
74
+ def test_rendering_a_checkbox_field_with_existing_value
75
+ @presentation.fields << {:foo => :checkbox}
76
+ @presentation.controller.params[:search] = {'foo' => {:value => '1'}}
77
+
78
+ assert_select "form input[type=checkbox][name='search[foo][value]'][value=1][checked=checked]"
79
+ end
80
+
81
+ def test_rendering_a_dropdown_field_with_existing_value
82
+ @presentation.fields << {:foo => {:type => :dropdown, :options => [["Dollar", "$"], ["Kroner", "DKK"]]}}
83
+ @presentation.controller.params[:search] = {'foo' => {:value => 'DKK'}}
84
+
85
+ assert_select "form select[name='search[foo][value]']" do
86
+ assert_select "option[value='$']"
87
+ assert_select "option[value='$'][selected='selected']", false
88
+ assert_select "option[value='DKK'][selected='selected']"
89
+ end
90
+ end
91
+
92
+ def test_rendering_a_dropdown_field_with_integers_and_existing_value
93
+ @presentation.fields << {:foo => {:type => :dropdown, :options => [["Dollar", 1], ["Kroner", 2]]}}
94
+ @presentation.controller.params[:search] = {'foo' => {:value => '2'}}
95
+
96
+ assert_select "form select[name='search[foo][value]']" do
97
+ assert_select "option[value='1']"
98
+ assert_select "option[value='1'][selected='selected']", false
99
+ assert_select "option[value='2'][selected='selected']"
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class FieldSetTest < Presenting::Test
4
+ def setup
5
+ @set = Presenting::FieldSet.new(Presenting::Attribute, :name, :value)
6
+ end
7
+
8
+ def test_reading_a_field_by_name
9
+ @set << "foo"
10
+ assert_equal "foo", @set["foo"].name
11
+ end
12
+
13
+ def test_pushing_a_field_by_name
14
+ @set << "foo"
15
+ assert_equal "foo", @set.first.name
16
+ end
17
+
18
+ def test_pushing_a_field_by_name_and_value
19
+ @set << {"foo" => :bar}
20
+ assert_equal "foo", @set.first.name
21
+ assert_equal :bar, @set.first.value
22
+ end
23
+
24
+ def test_pushing_a_field_by_name_and_options
25
+ @set << {"foo" => {:value => :bar}}
26
+ assert_equal "foo", @set.first.name
27
+ assert_equal :bar, @set.first.value
28
+ end
29
+
30
+ def test_adding_a_field_by_name
31
+ @set["foo"] = nil
32
+ assert_equal "foo", @set.first.name
33
+ end
34
+
35
+ def test_adding_a_field_by_name_and_value
36
+ @set["foo"] = :bar
37
+ assert_equal "foo", @set.first.name
38
+ assert_equal :bar, @set.first.value
39
+ end
40
+
41
+ def test_adding_a_field_by_name_and_options
42
+ @set["foo"] = {:value => :bar}
43
+ assert_equal "foo", @set.first.name
44
+ assert_equal :bar, @set.first.value
45
+ end
46
+ end