view_models 1.5.2
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.
- data/CHANGELOG +26 -0
- data/MIT-LICENSE +20 -0
- data/README.textile +242 -0
- data/Rakefile +47 -0
- data/VERSION.yml +4 -0
- data/generators/view_models/USAGE +6 -0
- data/generators/view_models/templates/README +1 -0
- data/generators/view_models/templates/spec/view_model_spec.rb +7 -0
- data/generators/view_models/templates/view_models/view_model.rb +5 -0
- data/generators/view_models/templates/views/_empty.html.haml +0 -0
- data/generators/view_models/templates/views/view_models/collection/_collection.html.erb +1 -0
- data/generators/view_models/templates/views/view_models/collection/_collection.html.haml +8 -0
- data/generators/view_models/templates/views/view_models/collection/_collection.text.erb +6 -0
- data/generators/view_models/templates/views/view_models/collection/_list.html.erb +1 -0
- data/generators/view_models/templates/views/view_models/collection/_list.html.haml +7 -0
- data/generators/view_models/templates/views/view_models/collection/_list.text.erb +6 -0
- data/generators/view_models/templates/views/view_models/collection/_pagination.html.haml +12 -0
- data/generators/view_models/templates/views/view_models/collection/_pagination.text.erb +3 -0
- data/generators/view_models/templates/views/view_models/collection/_table.html.haml +5 -0
- data/generators/view_models/templates/views/view_models/collection/_table.text.erb +10 -0
- data/generators/view_models/view_models_generator.rb +47 -0
- data/lib/extensions/active_record.rb +19 -0
- data/lib/extensions/model_reader.rb +115 -0
- data/lib/extensions/view.rb +24 -0
- data/lib/helpers/collection.rb +124 -0
- data/lib/helpers/rails.rb +59 -0
- data/lib/helpers/view.rb +22 -0
- data/lib/view_models/base.rb +268 -0
- data/lib/view_models/controller_extractor.rb +24 -0
- data/lib/view_models/path_store.rb +61 -0
- data/lib/view_models/render_options.rb +109 -0
- data/lib/view_models/view.rb +26 -0
- data/lib/view_models.rb +3 -0
- data/rails/init.rb +18 -0
- data/spec/integration/integration_spec.rb +269 -0
- data/spec/integration/models/sub_subclass.rb +14 -0
- data/spec/integration/models/subclass.rb +3 -0
- data/spec/integration/view_models/project.rb +14 -0
- data/spec/integration/view_models/sub_subclass.rb +42 -0
- data/spec/integration/view_models/subclass.rb +1 -0
- data/spec/integration/views/view_models/collection/_collection.html.erb +1 -0
- data/spec/integration/views/view_models/collection/_collection.text.erb +6 -0
- data/spec/integration/views/view_models/collection/_list.html.erb +1 -0
- data/spec/integration/views/view_models/collection/_list.text.erb +6 -0
- data/spec/integration/views/view_models/sub_subclass/_capture_in_template.erb +2 -0
- data/spec/integration/views/view_models/sub_subclass/_capture_in_view_model.erb +3 -0
- data/spec/integration/views/view_models/sub_subclass/_collection_example.html.erb +3 -0
- data/spec/integration/views/view_models/sub_subclass/_collection_example.text.erb +3 -0
- data/spec/integration/views/view_models/sub_subclass/_collection_item.html.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_collection_item.text.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_exists.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_exists.html.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_exists.text.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_exists_in_both.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_inner.also_explicit.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_inner.nesting.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_list_example.html.erb +3 -0
- data/spec/integration/views/view_models/sub_subclass/_list_example.text.erb +3 -0
- data/spec/integration/views/view_models/sub_subclass/_list_item.html.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_list_item.text.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_outer.explicit.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_outer.nesting.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/_part_that_is_dependent_on_the_view_model.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/show.html.erb +1 -0
- data/spec/integration/views/view_models/sub_subclass/show.text.erb +1 -0
- data/spec/integration/views/view_models/subclass/_exists_in_both.erb +1 -0
- data/spec/integration/views/view_models/subclass/_no_sub_subclass.erb +1 -0
- data/spec/integration/views/view_models/subclass/_not_found_in_sub_subclass.erb +1 -0
- data/spec/lib/extensions/active_record_spec.rb +31 -0
- data/spec/lib/extensions/model_reader_spec.rb +93 -0
- data/spec/lib/helpers/collection_spec.rb +196 -0
- data/spec/lib/helpers/rails_spec.rb +88 -0
- data/spec/lib/helpers/view_spec.rb +20 -0
- data/spec/lib/view_models/base_spec.rb +102 -0
- data/spec/lib/view_models/view_spec.rb +9 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/spec_helper_extensions.rb +13 -0
- metadata +156 -0
data/rails/init.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'extensions/active_record'
|
|
2
|
+
require 'extensions/model_reader'
|
|
3
|
+
|
|
4
|
+
require 'view_models'
|
|
5
|
+
require 'view_models/render_options'
|
|
6
|
+
require 'view_models/controller_extractor'
|
|
7
|
+
require 'view_models/path_store'
|
|
8
|
+
require 'view_models/base'
|
|
9
|
+
require 'view_models/view'
|
|
10
|
+
|
|
11
|
+
require 'helpers/view'
|
|
12
|
+
require 'helpers/rails'
|
|
13
|
+
require 'helpers/collection'
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# ActionController::Base.send :helper, ViewModels::Helpers::Rails
|
|
17
|
+
ActionController::Base.send :include, ViewModels::Helpers::Rails
|
|
18
|
+
ActionView::Base.send :include, ViewModels::Helpers::Rails
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../spec_helper')
|
|
2
|
+
|
|
3
|
+
require File.join(File.dirname(__FILE__), 'models/subclass')
|
|
4
|
+
require File.join(File.dirname(__FILE__), 'models/sub_subclass')
|
|
5
|
+
|
|
6
|
+
require 'helpers/rails'
|
|
7
|
+
ActionView::Base.send :include, ViewModels::Helpers::Rails
|
|
8
|
+
|
|
9
|
+
require 'view_models/base'
|
|
10
|
+
require File.join(File.dirname(__FILE__), 'view_models/project')
|
|
11
|
+
require File.join(File.dirname(__FILE__), 'view_models/subclass')
|
|
12
|
+
require File.join(File.dirname(__FILE__), 'view_models/sub_subclass')
|
|
13
|
+
|
|
14
|
+
require 'action_controller'
|
|
15
|
+
require 'action_controller/test_process'
|
|
16
|
+
|
|
17
|
+
class TestController < ActionController::Base; end
|
|
18
|
+
|
|
19
|
+
describe 'Integration' do
|
|
20
|
+
|
|
21
|
+
before(:each) do
|
|
22
|
+
begin
|
|
23
|
+
@controller = TestController.new
|
|
24
|
+
@controller.class.view_paths = ['spec/integration/views']
|
|
25
|
+
|
|
26
|
+
@logger = stub :logger, :null_object => true
|
|
27
|
+
@controller.logger = @logger
|
|
28
|
+
|
|
29
|
+
@request = ActionController::TestRequest.new
|
|
30
|
+
@response = ActionController::TestResponse.new
|
|
31
|
+
@controller.request = @request
|
|
32
|
+
@controller.response = @response
|
|
33
|
+
|
|
34
|
+
# TODO Make separate contexts, one where the controller has rendered, one where it has not.
|
|
35
|
+
#
|
|
36
|
+
# Let the Controller generate a view instance.
|
|
37
|
+
#
|
|
38
|
+
# @controller.process @request, @response
|
|
39
|
+
|
|
40
|
+
@view = ActionView::Base.new @controller.class.view_paths, {}, @controller
|
|
41
|
+
@model = SubSubclass.new
|
|
42
|
+
@model.id = :some_id
|
|
43
|
+
@view_model = ViewModels::SubSubclass.new @model, @view
|
|
44
|
+
# rescue Exception => e
|
|
45
|
+
# puts e.message
|
|
46
|
+
# puts e.backtrace
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
before(:all) { puts "\n#{self.send(:description_args)[0]}:" }
|
|
51
|
+
|
|
52
|
+
describe 'ActiveRecord Extensions' do
|
|
53
|
+
before(:each) do
|
|
54
|
+
@view_model.extend ViewModels::Extensions::ActiveRecord
|
|
55
|
+
end
|
|
56
|
+
it 'should delegate the id' do
|
|
57
|
+
@view_model.id.should == :some_id
|
|
58
|
+
end
|
|
59
|
+
it 'should delegate the id' do
|
|
60
|
+
@view_model.dom_id.should == 'sub_subclass_some_id'
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe 'view_model_for' do
|
|
65
|
+
context 'view model' do
|
|
66
|
+
it 'should be available' do
|
|
67
|
+
lambda { @view_model.view_model_for @model }.should_not raise_error
|
|
68
|
+
end
|
|
69
|
+
it 'should return the right one' do
|
|
70
|
+
@view_model.view_model_for(@model).should be_kind_of(ViewModels::SubSubclass)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
describe 'view_model_class_for' do
|
|
75
|
+
context 'view model' do
|
|
76
|
+
it 'should be available' do
|
|
77
|
+
lambda { @view_model.view_model_class_for @model }.should_not raise_error
|
|
78
|
+
end
|
|
79
|
+
it 'should return the right class' do
|
|
80
|
+
@view_model.view_model_class_for(@model).should == ViewModels::SubSubclass
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe 'capture in view model method' do
|
|
86
|
+
context 'template' do
|
|
87
|
+
it 'should capture the content of the block' do
|
|
88
|
+
@view_model.render_as(:capture_in_template).should == 'Capturing: A Pirate!'
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
context 'in view model' do
|
|
92
|
+
it 'should capture the content of the block' do
|
|
93
|
+
@view_model.render_as(:capture_in_view_model).should == 'Capturing: A Pirate!'
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe 'controller context' do
|
|
99
|
+
it 'should work' do
|
|
100
|
+
controller = ActionController::Base.new
|
|
101
|
+
|
|
102
|
+
lambda {
|
|
103
|
+
ViewModels::SubSubclass.new @model, controller
|
|
104
|
+
}.should_not raise_error
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
describe 'view_model_for inclusion in view' do
|
|
109
|
+
it 'should be included' do
|
|
110
|
+
view = ActionView::Base.new
|
|
111
|
+
|
|
112
|
+
lambda {
|
|
113
|
+
view.view_model_for @model
|
|
114
|
+
}.should_not raise_error
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe 'collection rendering' do
|
|
119
|
+
context 'default format' do
|
|
120
|
+
it 'should render a html list' do
|
|
121
|
+
@view_model.render_as(:list_example).should == "<ol class=\"collection\"><li>_list_item.html.erb</li><li>_list_item.html.erb</li></ol>"
|
|
122
|
+
end
|
|
123
|
+
it 'should render a html collection' do
|
|
124
|
+
@view_model.render_as(:collection_example).should == "<ul class=\"collection\"><li>_collection_item.html.erb</li><li>_collection_item.html.erb</li></ul>"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
context 'format html' do
|
|
128
|
+
it 'should render a html list' do
|
|
129
|
+
@view_model.render_as(:list_example, :format => :html).should == "<ol class=\"collection\"><li>_list_item.html.erb</li><li>_list_item.html.erb</li></ol>"
|
|
130
|
+
end
|
|
131
|
+
it 'should render a html collection' do
|
|
132
|
+
@view_model.render_as(:collection_example, :format => :html).should == "<ul class=\"collection\"><li>_collection_item.html.erb</li><li>_collection_item.html.erb</li></ul>"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
context 'format text' do
|
|
136
|
+
it 'should render a text list' do
|
|
137
|
+
@view_model.render_as(:list_example, :format => :text).should == '_list_item.text.erb\n_list_item.text.erb'
|
|
138
|
+
end
|
|
139
|
+
it 'should render a text collection' do
|
|
140
|
+
@view_model.render_as(:collection_example, :format => :text).should == '_collection_item.text.erb_collection_item.text.erb'
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe 'model attributes' do
|
|
146
|
+
it 'should pass through unfiltered attributes' do
|
|
147
|
+
@view_model.some_untouched_attribute.should == :some_value
|
|
148
|
+
end
|
|
149
|
+
it 'should filter some attributes' do
|
|
150
|
+
@view_model.some_filtered_attribute.should == '%3Cscript%3Efilter+me%3C%2Fscript%3E'
|
|
151
|
+
end
|
|
152
|
+
it 'should filter some attributes multiple times' do
|
|
153
|
+
@view_model.some_doubly_doubled_attribute.should == 'blahblahblahblah'
|
|
154
|
+
end
|
|
155
|
+
it 'should filter some attributes multiple times correctly' do
|
|
156
|
+
@view_model.some_mangled_attribute.should == 'DCBDCB'
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
describe 'controller_method' do
|
|
161
|
+
it 'should delegate to the context' do
|
|
162
|
+
@view_model.logger.should == @logger
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
describe "render_template" do
|
|
167
|
+
it "should render the right template" do
|
|
168
|
+
@view_model.render_template(:show).should == 'show.html.erb'
|
|
169
|
+
end
|
|
170
|
+
it "should render the right template with format" do
|
|
171
|
+
@view_model.render_template(:show, :format => :text).should == 'show.text.erb'
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
describe 'render_as' do
|
|
176
|
+
describe 'render_the alias' do
|
|
177
|
+
it 'should also render' do
|
|
178
|
+
@view_model.render_the(:part_that_is_dependent_on_the_view_model).should == '_part_that_is_dependent_on_the_view_model.erb'
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
describe "explicit partial rendering" do
|
|
182
|
+
it "should render the right partial" do
|
|
183
|
+
# If one wants explicit template rendering, he needs to work more.
|
|
184
|
+
# Let's be opinionated here :)
|
|
185
|
+
#
|
|
186
|
+
@view_model.render_as(:partial => 'view_models/sub_subclass/inner', :format => :nesting).should == '_inner.nesting.erb'
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
describe "nesting" do
|
|
190
|
+
it "should render the right nested template, with an explicitly defined format (see template)" do
|
|
191
|
+
@view_model.render_as(:outer, :format => :explicit).should == '_inner.also_explicit.erb'
|
|
192
|
+
end
|
|
193
|
+
it "should render the right nested template, respecting the already defined format" do
|
|
194
|
+
@view_model.render_as(:outer, :format => :nesting).should == '_inner.nesting.erb'
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
describe 'template inheritance' do
|
|
198
|
+
it 'should raise ViewModels::MissingTemplateError if template is not found' do
|
|
199
|
+
lambda { @view_model.render_as(:this_template_does_not_exist_at_allllll) }.should raise_error(ViewModels::MissingTemplateError, "No template '_this_template_does_not_exist_at_allllll' with default format found.")
|
|
200
|
+
end
|
|
201
|
+
it 'should raise ViewModels::MissingTemplateError if template is not found, with specific path' do
|
|
202
|
+
lambda { @view_model.render_as(:partial => 'view_models/sub_subclass/this_template_does_not_exist_at_allllll') }.should raise_error(ViewModels::MissingTemplateError, "No template 'view_models/sub_subclass/_this_template_does_not_exist_at_allllll' with default format found.")
|
|
203
|
+
end
|
|
204
|
+
it 'should raise ViewModels::MissingTemplateError if template is not found, with format' do
|
|
205
|
+
lambda { @view_model.render_as(:this_template_does_not_exist_at_allllll, :format => :gaga) }.should raise_error(ViewModels::MissingTemplateError, "No template '_this_template_does_not_exist_at_allllll' with format gaga found.")
|
|
206
|
+
end
|
|
207
|
+
it "should use its own template" do
|
|
208
|
+
@view_model.render_as(:exists).should == '_exists.html.erb' # The default
|
|
209
|
+
end
|
|
210
|
+
it "should use the subclass' template" do
|
|
211
|
+
@view_model.render_as(:no_sub_subclass).should == '_no_sub_subclass.erb'
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
describe 'format' do
|
|
215
|
+
it 'should render html' do
|
|
216
|
+
@view_model.render_as(:exists, :format => nil).should == '_exists.html.erb' # the default
|
|
217
|
+
end
|
|
218
|
+
it 'should render erb' do
|
|
219
|
+
@view_model.render_as(:exists, :format => '').should == '_exists.erb'
|
|
220
|
+
end
|
|
221
|
+
it 'should render text' do
|
|
222
|
+
@view_model.render_as(:exists, :format => :text).should == '_exists.text.erb'
|
|
223
|
+
end
|
|
224
|
+
it 'should render html' do
|
|
225
|
+
@view_model.render_as(:exists, :format => :html).should == '_exists.html.erb'
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
describe 'locals' do
|
|
229
|
+
it 'should render html' do
|
|
230
|
+
@view_model.render_as(:exists, :locals => { :local_name => :some_local }).should == '_exists.html.erb with some_local'
|
|
231
|
+
end
|
|
232
|
+
it 'should render html' do
|
|
233
|
+
@view_model.render_as(:exists, :format => nil, :locals => { :local_name => :some_local }).should == '_exists.html.erb with some_local'
|
|
234
|
+
end
|
|
235
|
+
it 'should render text' do
|
|
236
|
+
@view_model.render_as(:exists, :format => '', :locals => { :local_name => :some_local }).should == '_exists.erb with some_local'
|
|
237
|
+
end
|
|
238
|
+
it 'should render text' do
|
|
239
|
+
@view_model.render_as(:exists, :format => :text, :locals => { :local_name => :some_local }).should == '_exists.text.erb with some_local'
|
|
240
|
+
end
|
|
241
|
+
it 'should render html' do
|
|
242
|
+
@view_model.render_as(:exists, :format => :html, :locals => { :local_name => :some_local }).should == '_exists.html.erb with some_local'
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
describe 'memoizing' do
|
|
246
|
+
it 'should memoize and not generate always a new path' do
|
|
247
|
+
@view_model.class.should_receive(:generate_template_path_from).once
|
|
248
|
+
|
|
249
|
+
@view_model.render_as :not_found_in_sub_subclass
|
|
250
|
+
@view_model.render_as :not_found_in_sub_subclass
|
|
251
|
+
@view_model.render_as :not_found_in_sub_subclass
|
|
252
|
+
@view_model.render_as :not_found_in_sub_subclass
|
|
253
|
+
@view_model.render_as :not_found_in_sub_subclass
|
|
254
|
+
end
|
|
255
|
+
it 'should render the right one' do
|
|
256
|
+
@view_model.render_as :exists_in_both
|
|
257
|
+
@view_model.render_as(:exists_in_both).should == 'in sub subclass'
|
|
258
|
+
|
|
259
|
+
other_view_model = ViewModels::Subclass.new Subclass.new, @view
|
|
260
|
+
other_view_model.render_as :exists_in_both
|
|
261
|
+
other_view_model.render_as(:exists_in_both).should == 'in subclass'
|
|
262
|
+
|
|
263
|
+
@view_model.render_as :exists_in_both
|
|
264
|
+
@view_model.render_as(:exists_in_both).should == 'in sub subclass'
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class SubSubclass
|
|
2
|
+
|
|
3
|
+
attr_accessor :id
|
|
4
|
+
|
|
5
|
+
attr_reader :some_untouched_attribute, :some_filtered_attribute, :some_doubly_doubled_attribute, :some_mangled_attribute
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@some_untouched_attribute = :some_value
|
|
9
|
+
@some_filtered_attribute = '<script>filter me</script>'
|
|
10
|
+
@some_doubly_doubled_attribute = 'blah'
|
|
11
|
+
@some_mangled_attribute = 'abcd'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class ViewModels::Project < ViewModels::Base
|
|
2
|
+
|
|
3
|
+
helper :all
|
|
4
|
+
|
|
5
|
+
# helper ActionView::Helpers::CaptureHelper
|
|
6
|
+
|
|
7
|
+
helper ViewModels::Helpers::Rails
|
|
8
|
+
helper ViewModels::Helpers::View
|
|
9
|
+
|
|
10
|
+
# def output_buffer= b
|
|
11
|
+
# view.output_buffer = b
|
|
12
|
+
# end
|
|
13
|
+
|
|
14
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
class ViewModels::SubSubclass < ViewModels::Subclass
|
|
2
|
+
|
|
3
|
+
controller_method :logger
|
|
4
|
+
|
|
5
|
+
model_reader :some_untouched_attribute
|
|
6
|
+
model_reader :some_filtered_attribute, :filter_through => :h
|
|
7
|
+
model_reader :some_doubly_doubled_attribute, :filter_through => [:doubled]*2
|
|
8
|
+
model_reader :some_mangled_attribute, :filter_through => [:reverse, :cutoff, :doubled, :upcase]
|
|
9
|
+
|
|
10
|
+
# h as we know it.
|
|
11
|
+
#
|
|
12
|
+
def h v
|
|
13
|
+
CGI.escape v
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Multiplies the text by 2.
|
|
17
|
+
#
|
|
18
|
+
def doubled text
|
|
19
|
+
text*2
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Cuts off the last 2 characters. Or all, if less than size 2.
|
|
23
|
+
#
|
|
24
|
+
def cutoff text
|
|
25
|
+
text[0..-2]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def reverse text
|
|
29
|
+
text.reverse
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def upcase text
|
|
33
|
+
text.upcase
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Captures the block as a string.
|
|
37
|
+
#
|
|
38
|
+
def capture_block &block
|
|
39
|
+
capture &block
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class ViewModels::Subclass < ViewModels::Project; end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<ul class="collection"><%- collection.each do |item| -%><%- view_model = view_model_for item -%><li><%- options = template_format ? { :format => template_format } : {} -%><%= view_model.render_as template_name, options -%></li><%= separator unless item == collection.last %><%- end -%></ul>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<%- collection.each do |item| -%>
|
|
2
|
+
<%- view_model = view_model_for item -%>
|
|
3
|
+
<%- options = (template_format ? { :format => template_format } : {}) -%>
|
|
4
|
+
<%= view_model.render_as template_name, options -%>
|
|
5
|
+
<%= separator unless item == collection.entries.last -%>
|
|
6
|
+
<%- end -%>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<ol class="collection"><%- collection.each do |item| -%><%- view_model = view_model_for item -%><li><%- options = (template_format ? { :format => template_format } : {}) -%><%= view_model.render_as template_name, options -%></li><%= separator unless item == collection.last %><%- end -%></ol>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<% collection.each do |item| -%>
|
|
2
|
+
<% view_model = view_model_for item -%>
|
|
3
|
+
<%- options = (template_format ? { :format => template_format } : {}) -%>
|
|
4
|
+
<%= view_model.render_as template_name, options -%>
|
|
5
|
+
<%= separator || '\n' unless item == collection.entries.last -%>
|
|
6
|
+
<% end -%>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_collection_item.html.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_collection_item.text.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_exists.erb<%= " with #{local_name}" if defined?(local_name) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_exists.html.erb<%= " with #{local_name}" if defined?(local_name) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_exists.text.erb<%= " with #{local_name}" if defined?(local_name) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
in sub subclass
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_inner.also_explicit.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_inner.nesting.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_list_item.html.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_list_item.text.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= view_model.render_as(:inner, :format => :also_explicit) -%>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= view_model.render_as :inner -%>
|
data/spec/integration/views/view_models/sub_subclass/_part_that_is_dependent_on_the_view_model.erb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_part_that_is_dependent_on_the_view_model.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
show.html.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
show.text.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
in subclass
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_no_sub_subclass.erb
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_not_found_in_sub_subclass.erb
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe ViewModels::Extensions::ActiveRecord do
|
|
4
|
+
|
|
5
|
+
describe "to_param" do
|
|
6
|
+
before(:each) do
|
|
7
|
+
@model = stub :model
|
|
8
|
+
@view_model = ViewModels::Base.new @model, nil
|
|
9
|
+
@view_model.extend ViewModels::Extensions::ActiveRecord
|
|
10
|
+
end
|
|
11
|
+
it "should delegate to_param to the model" do
|
|
12
|
+
@model.should_receive(:to_param).once
|
|
13
|
+
|
|
14
|
+
@view_model.to_param
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should delegate id to the model" do
|
|
18
|
+
@model.should_receive(:id).once
|
|
19
|
+
|
|
20
|
+
@view_model.id
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should delegate dom_id to ActionController::RecordIdentifier" do
|
|
24
|
+
ActionController::RecordIdentifier.should_receive(:dom_id).once
|
|
25
|
+
|
|
26
|
+
@view_model.dom_id
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../../spec_helper')
|
|
2
|
+
|
|
3
|
+
require 'extensions/model_reader'
|
|
4
|
+
|
|
5
|
+
describe ViewModels::Extensions::ModelReader do
|
|
6
|
+
|
|
7
|
+
class ModelReaderModel < Struct.new(:some_model_value); end
|
|
8
|
+
|
|
9
|
+
describe ".model_reader" do
|
|
10
|
+
before(:each) do
|
|
11
|
+
@model = ModelReaderModel.new
|
|
12
|
+
@view_model = ViewModels::Base.new(@model, nil)
|
|
13
|
+
class << @view_model
|
|
14
|
+
def a(s); s << 'a' end
|
|
15
|
+
def b(s); s << 'b' end
|
|
16
|
+
end
|
|
17
|
+
@model.some_model_value = 's'
|
|
18
|
+
end
|
|
19
|
+
it "should call filters in a given pattern" do
|
|
20
|
+
@view_model.class.model_reader :some_model_value, :filter_through => [:a, :b, :a, :a]
|
|
21
|
+
|
|
22
|
+
@view_model.some_model_value.should == 'sabaa'
|
|
23
|
+
end
|
|
24
|
+
it "should pass through the model value if no filters are installed" do
|
|
25
|
+
@view_model.class.model_reader :some_model_value
|
|
26
|
+
|
|
27
|
+
@view_model.some_model_value.should == 's'
|
|
28
|
+
end
|
|
29
|
+
it "should call filters in a given pattern" do
|
|
30
|
+
@view_model.class.model_reader [:some_model_value], :filter_through => [:a, :b, :a, :a]
|
|
31
|
+
|
|
32
|
+
@view_model.some_model_value.should == 'sabaa'
|
|
33
|
+
end
|
|
34
|
+
it "should handle a single filter" do
|
|
35
|
+
@view_model.class.model_reader :some_model_value, :filter_through => :a
|
|
36
|
+
|
|
37
|
+
lambda { @view_model.some_model_value }.should_not raise_error
|
|
38
|
+
end
|
|
39
|
+
it "should handle an array of readers" do
|
|
40
|
+
@view_model.class.model_reader [:some_model_value, :some_other_model_value], :filter_through => :a
|
|
41
|
+
|
|
42
|
+
lambda { @view_model.some_model_value }.should_not raise_error
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe 'FilteredDelegationInstaller' do
|
|
47
|
+
before(:each) do
|
|
48
|
+
@model = ModelReaderModel.new
|
|
49
|
+
end
|
|
50
|
+
context 'with filters' do
|
|
51
|
+
before(:each) do
|
|
52
|
+
@options = ViewModels::Extensions::ModelReader::Options.new :some_attribute_name, :filter_through => [:filter1, :filter2]
|
|
53
|
+
@installer = ViewModels::Extensions::ModelReader::FilteredDelegationInstaller.new @model, @options
|
|
54
|
+
end
|
|
55
|
+
it 'should have a correct filter definition' do
|
|
56
|
+
@installer.reader_definition_for(:some_attribute).should == 'def some_attribute; filter2(filter1(model.some_attribute)); end'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
context 'without filters' do
|
|
60
|
+
before(:each) do
|
|
61
|
+
@options = ViewModels::Extensions::ModelReader::Options.new :some_attribute_name
|
|
62
|
+
@installer = ViewModels::Extensions::ModelReader::FilteredDelegationInstaller.new @model, @options
|
|
63
|
+
end
|
|
64
|
+
it 'should have a correct filter definition' do
|
|
65
|
+
@installer.reader_definition_for(:some_attribute).should == 'def some_attribute; model.some_attribute; end'
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe 'Options' do
|
|
71
|
+
context 'without filters' do
|
|
72
|
+
before(:each) do
|
|
73
|
+
@options = ViewModels::Extensions::ModelReader::Options.new :some_attribute_name
|
|
74
|
+
end
|
|
75
|
+
describe 'split' do
|
|
76
|
+
it 'should return the right values' do
|
|
77
|
+
@options.to_a.should == [[:some_attribute_name], []]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
context 'with filters' do
|
|
82
|
+
before(:each) do
|
|
83
|
+
@options = ViewModels::Extensions::ModelReader::Options.new :some_attribute_name, :filter_through => [:filter1, :filter2]
|
|
84
|
+
end
|
|
85
|
+
describe 'split' do
|
|
86
|
+
it 'should return the right values, with flipped options' do
|
|
87
|
+
@options.to_a.should == [[:some_attribute_name], [:filter2, :filter1]]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|