view_models 1.5.6 → 1.5.7

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/README.textile CHANGED
@@ -1,22 +1,16 @@
1
- h1. ViewModels for Rails
1
+ h1. ViewModels
2
2
 
3
- h2. Previous contributors
3
+ A view model/representer solution for Rails.
4
4
 
5
- Code:
5
+ h2. Features
6
6
 
7
- "Kaspar":http://github.com/kschiess @http://github.com/kschiess@, for the first, and foundation-laying version.
8
-
9
- "Niko":http://github.com/niko @http://github.com/niko@, for handling collections and better Helpers handling.
10
-
11
- "Andi":http://github.com/andi @http://github.com/andi@, for refactoring it into a cleaner structure.
12
-
13
- Inspiration:
14
-
15
- "Severin":http://github.com/severin @http://github.com/severin@, for bits and pieces here and there.
16
-
17
- "rainhead":http://github.com/rainhead @http://github.com/rainhead@, for the idea to subclass ActionView::Base.
18
-
19
- Important note: These guys rock! :)
7
+ * Polymorph view model objects that correspond to model objects.
8
+ * View model specific templates.
9
+ * Hierarchical Template Rendering: Allows generalized templates for a class tree of view models.
10
+ * Helper methods directly on the view models.
11
+ * No view related code in the models.
12
+ * A clean API for use in Rails.
13
+ * 100% rcov coverage, nice metrics, gallons of blood and sweat by excellent contributors.
20
14
 
21
15
  h2. Installation
22
16
 
@@ -24,7 +18,7 @@ h3. Rails Plugin
24
18
 
25
19
  @script/plugin install git://github.com/floere/view_models.git@
26
20
 
27
- h3. Gem for use in Rails
21
+ h3. Gem (for use in Rails)
28
22
 
29
23
  @gem install view_models@
30
24
 
@@ -34,221 +28,13 @@ and then adding the line
34
28
 
35
29
  in your environment.rb.
36
30
 
37
- h2. Description
38
-
39
- A possible view_model solution, i.e. no view logic in model code.
40
-
41
- h2. Feedback
42
-
43
- Ask/Write florian.hanke@gmail.com if you have questions/feedback, thanks! :)
44
- Fork if you have improvements. Send me a pull request, it is much appreciated.
45
-
46
- h2. Problem
47
-
48
- Display Methods are not well placed either in
49
- * models: Violation of the MVC principle.
50
- * helpers: No Polymorphism.
51
-
52
- h2. Solution
53
-
54
- A thin proxy layer over a model, with access to the controller, used by the view or controller.
55
-
56
- @The view@ -> to @the view model@ which in turn -> @the model@ and -> @the controller@
57
-
58
- h2. Examples & What you can do
59
-
60
- h3. A quick one
61
-
62
- In the view:
63
- <pre><code>user = view_model_for @user
64
- %h1= "You, #{user.full_name}, the user"
65
- %h2 This is how you look as a search result:
66
- = user.render_as :result
67
- %h2 This is how you look as a Vcard:
68
- = user.render_as :vcard</code></pre>
69
- In the view model:
70
- <pre><code>class ViewModels::User < ViewModels::Project
71
- model_reader :first_name, :last_name
72
- def full_name
73
- "#{last_name}, #{first_name}"
74
- end
75
- end</code></pre>
76
- In the model:
77
- <pre><code>class User < ActiveRecord::Base
78
- end</code></pre>
79
- Also, there are two partials in @app/views/view_models/user/@, @_result.html.haml@ and @_vcard.html.haml@ that define how the result of @user.render_as :result@ and @user.render_as :vcard@ look. The ViewModel can be accessed inside the view by using the local variable @view_model@.
80
-
81
- h3. Getting a view_model in a view or a controller.
82
-
83
- Call view_model_for: @view_model_instance = view_model_for model_instance@
84
- By convention, uses @ViewModels::Model::Class::Name@, thus prefixing @ViewModels::@ to the model class name.
85
-
86
- Note: You can override @specific_view_model_class_for@ to change the mapping of model to class, or make it dynamic.
87
-
88
- h3. Getting a collection view model in a view.
89
-
90
- The collection view_model renders each of the given items with its view_model.
91
-
92
- Call collection_view_model_for: @collection_view_model_instance = collection_view_model_for enumerable_containing_model_instances@
93
-
94
- Rendering a list: @collection_view_model_instance.list@
95
-
96
- Rendering a collection: @collection_view_model_instance.collection@
97
-
98
- Rendering a table: @collection_view_model_instance.table@
99
-
100
- Rendering a pagination: @collection_view_model_instance.pagination@
101
- Note: Only works if the passed parameter for @collection_view_model_for@ is a @PaginationEnumeration@.
102
-
103
- Important note:
104
- As of yet it is needed to copy the templates/views/view_models/collection
105
- directory to the corresponding location in app/views/view_models/collection.
106
- This is only needed if you wish to use the collection view model.
107
- The collections are automatically copied if you use the generator.
108
-
109
- Note: Rewrite the collection templates as needed, they are rather basic.
110
-
111
- h3. Writing filtered delegate methods on the view model.
112
-
113
- Will create two delegate methods first_name and last_name that delegate to the model: @model_reader :first_name, :last_name@
114
-
115
- Will create a description delegate method that filters the model value through h: @model_reader :description, :filter_through => :h@
116
-
117
- Will create a description delegate method that filters the model value through first textilize, then h: @model_reader :description, :filter_through => [:textilize, :h]@
118
-
119
- Will create both a first_name and last_name delegate method that filters the model value through first textilize, then h: @model_reader :first_name, :last_name, :filter_through => [:textilize, :h]@
120
- Note: Filter methods can be any method on the view_model with arity 1.
121
-
122
- h3. Rendering view model templates
123
-
124
- Use @render_as(template_name, options)@.
125
-
126
- Gets a @ViewModels::Model::Class@ instance: @view_model = view_model_for Model::Class.new@
127
-
128
- Gets a @ViewModels::<model_instance.class.name>@ instance: @view_model = view_model_for model_instance@
129
-
130
- Renders the 'example' partial in view_models/model/class: @view_model.render_as :example@
131
- Note: Renders a format depending on the request. ../index.text will render example.text.erb.
132
-
133
- Renders the 'example.text.erb' partial in view_models/model/class: @view_model.render_as :example, :format => :text@
134
- Note: If the partial cannot be found, it will traverse the view model hierarchy upwards to find a partial template.
135
-
136
- Locals can be passed through as usual: @view_model.render_as :example, :format => :text, :locals => { :name => value }@
137
-
138
- h3. Rails Helpers in ViewModels
139
-
140
- Use @helper@ as you would in the controller.
141
- @helper ActionView::Helpers::UrlHelper@
142
- @helper ApplicationHelper@
143
- Note: It is helpful to create a superclass to all view models in the project with generally used helpers.
144
- We use @ViewModels::Project@ a lot, for example. See example below.
145
-
146
- h3. Controller Delegate Methods
147
-
148
- Use @controller_method(*args)@.
149
-
150
- Delegates current_user and logger on the view_model to the controller: @controller_method :current_user, :logger@
151
-
152
- h2. The Generator
153
-
154
- Generates view model class, spec, and views. Use as follows:
155
-
156
- @script/generate view_models <view model class name>@
157
- @script/generate view_models User@
158
-
159
- @script/generate view_models <view model class name> <partials for render_as, separated by space>@
160
- @script/generate view_models User compact extensive list_item table_item@
161
-
162
- h2. One Big Fat Example
163
-
164
- The following classes all have specs of course ;) But are not shown since they don't help the example.
165
-
166
- @ViewModels@ superclass for this project.
167
-
168
- We include all of Rails' helpers for the view models in this project.
169
- Also, we include the @ApplicationHelper@.
170
-
171
- We delegate @logger@ and @current_user@ calls in the view models to the active controller.
172
-
173
- <pre>
174
- <code>
175
- class ViewModels::Project < ViewModels::Base
176
-
177
- # Our ApplicationHelper.
178
- #
179
- helper ApplicationHelper
180
-
181
- # We want to be able to call view_model_for in our view_models.
182
- #
183
- helper ViewModels::Helpers::Rails
184
-
185
- # Include all common view helpers.
186
- #
187
- helper ViewModels::Helpers::View
188
-
189
- # We want to be able to use id, dom_id, to_param on the view model.
190
- #
191
- # Note: Overrides the standard dom_id method from the RecordIdentificationHelper.
192
- #
193
- include ViewModels::Extensions::ActiveRecord
194
-
195
- controller_method :logger, :current_user
196
-
197
- end
198
-
199
- # All items have a description that needs to be filtered by textilize.
200
- #
201
- class ViewModels::Item < ViewModels::Project
202
- model_reader :description, :filter_through => :textilize
203
- # Use price in the view as follows:
204
- # = view_model.price - will display e.g. 16.57 CHF, since it is filtered first through localize_currency
205
- model_reader :price, :filter_through => :localize_currency
206
-
207
- # Converts a database price tag to the users chosen value, with the users preferred currency appended.
208
- # If the user is Swiss, localize_currency will convert 10 Euros to "16.57 CHF"
209
- #
210
- def localize_currency(price_in_euros)
211
- converted_price = current_user.convert_price(price_in_euros)
212
- "#{converted_price} #{current_user.currency.to_s}"
213
- end
214
- end
215
-
216
- # This class also has partial templates in the directory
217
- # app/views/view_models/book
218
- # that are called
219
- # _cart_item.html.haml
220
- # _cart_item.text.erb
221
- #
222
- # Call view_model_for on a book in the view or controller to get this view_model.
223
- #
224
- class ViewModels::Book < ViewModels::Item
225
- model_reader :author, :title, :pages
226
- model_reader :excerpt, :filter_through => :textilize
227
-
228
- def header
229
- content_tag(:h1, "#{author} – #{title}")
230
- end
231
-
232
- def full_description
233
- content_tag(:p, "#{excerpt} #{description}", :class => 'description full')
234
- end
235
- end
31
+ h2. Links Galore!
236
32
 
237
- # This class also has partial templates in the directory
238
- # app/views/view_models/toy
239
- # that are called
240
- # _cart_item.html.haml
241
- # _cart_item.text.erb
242
- #
243
- # Call view_model_for on a toy in the view or controller to get this view_model.
244
- #
245
- class ViewModels::Toy < ViewModels::Item
246
- model_reader :starting_age, :small_dangerous_parts
247
-
248
- def obligatory_parental_warning
249
- "Warning, this toy can only be used by kids ages #{starting_age} and up. Your department of health. Thank you."
250
- end
251
-
252
- end
253
- </code>
254
- </pre>
33
+ "Usage, Examples, In-depth Infos [Wiki]":http://wiki.github.com/floere/view_models/
34
+ "Reference [RDoc]":http://rdoc.info/projects/floere/view_models
35
+ "Gem [RubyGems.org]":http://rubygems.org/gems/view_models
36
+ "Mailing List":http://groups.google.com/group/view_models/topics
37
+ "Bug Tracker":http://github.com/floere/view_models/issues
38
+ "Metrics":http://getcaliper.com/caliper/project?repo=git://github.com/floere/view_models.git
39
+ "Source [Github]":http://github.com/floere/view_models
40
+ "Homepage":http://floere.github.com/view_models/
data/TODO.textile CHANGED
@@ -1,4 +1,5 @@
1
1
  h1. Next up
2
2
 
3
- * Explore possibilities to include Modules in hierarchical rendering.
4
- * Encapsule the rather bloated hierarchical rendering in a HierarchicalRendering object that mediates the whole rendering process.
3
+ * Encapsule the rather bloated hierarchical rendering in a HierarchicalRendering object that mediates the whole rendering process.
4
+
5
+ --* Explore possibilities to include Modules in hierarchical rendering.--
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 5
3
- :patch: 6
3
+ :patch: 7
4
4
  :major: 1
@@ -1,10 +1,10 @@
1
1
  module ModulesInRenderHierarchy
2
-
2
+
3
3
  def self.included klass
4
4
  klass.extend ClassMethods
5
5
  klass.metaclass.alias_method_chain :include, :superclass_override
6
6
  end
7
-
7
+
8
8
  module ClassMethods
9
9
  def include_with_superclass_override mod
10
10
  original_superclass = superclass
@@ -17,5 +17,5 @@ module ModulesInRenderHierarchy
17
17
  end
18
18
  end
19
19
  end
20
-
20
+
21
21
  end
@@ -4,7 +4,7 @@ module ViewModels
4
4
  #
5
5
  module RenderOptions
6
6
 
7
- # Hold a number of options for rendering.
7
+ # Base class for Partial and Template.
8
8
  #
9
9
  class Base
10
10
 
@@ -57,35 +57,43 @@ module ViewModels
57
57
  template_name.to_s.include?('/') ? specific_path(template_name) : incomplete_path(template_name)
58
58
  end
59
59
 
60
- #
61
- #
62
- def deoptionize template_name
63
- if template_name.kind_of?(Hash)
64
- @options.merge! template_name
65
- @options.delete :partial
66
- else
67
- template_name
68
- end
69
- end
70
-
71
- #
60
+ # Specific path is a specifically named view path, with slashes.
72
61
  #
73
62
  def specific_path name
74
63
  self.path = File.dirname name
75
64
  self.name_with_prefix = File.basename name
76
65
  end
77
66
 
78
- #
67
+ # Incomplete path is a view path without slashes. The view models will
68
+ # try to find out where to take the template from.
79
69
  #
80
70
  def incomplete_path name
81
71
  self.path = nil
82
72
  self.name_with_prefix = name
83
73
  end
84
74
 
75
+ # Add the prefix to the template name.
76
+ #
77
+ # Note: Will add an underscore if it's a partial.
78
+ #
85
79
  def name_with_prefix= name
86
80
  self.name = "#{self.prefix}#{name}"
87
81
  end
88
82
 
83
+ # Extracts the template name from the given parameter.
84
+ #
85
+ # If it's a hash, it will remove and use the :partial option.
86
+ # If not, it will use that.
87
+ #
88
+ def deoptionize template_name
89
+ if template_name.kind_of?(Hash)
90
+ @options.merge! template_name
91
+ @options.delete :partial
92
+ else
93
+ template_name
94
+ end
95
+ end
96
+
89
97
  end
90
98
 
91
99
  # A specific container for partial rendering.
@@ -60,7 +60,7 @@ describe 'Integration' do
60
60
  # end
61
61
  # end
62
62
  # end
63
-
63
+
64
64
  describe 'ActiveRecord Extensions' do
65
65
  before(:each) do
66
66
  @view_model.extend ViewModels::Extensions::ActiveRecord
@@ -1,7 +1,7 @@
1
1
  module ModuleForRendering
2
-
2
+
3
3
  def module_method
4
4
  "Hello!"
5
5
  end
6
-
6
+
7
7
  end
@@ -32,8 +32,6 @@ describe ViewModels::Helpers::Rails do
32
32
  specific_view_model_mapping.should == {}
33
33
  end
34
34
  it "should raise an ArgumentError on an non-mapped model" do
35
- # TODO really clear enough that one should provide a ViewModel with an initializer with 2 params?
36
- #
37
35
  class SomeViewModelClass; end
38
36
  specific_view_model_mapping[String] = SomeViewModelClass
39
37
  lambda {
@@ -43,8 +41,6 @@ describe ViewModels::Helpers::Rails do
43
41
  end
44
42
  describe "no specific mapping" do
45
43
  it "should raise on an non-mapped model" do
46
- # TODO really clear enough that the view model class is missing?
47
- #
48
44
  lambda {
49
45
  view_model_for(42)
50
46
  }.should raise_error(NameError, "uninitialized constant ViewModels::Fixnum")
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 5
8
- - 6
9
- version: 1.5.6
8
+ - 7
9
+ version: 1.5.7
10
10
  platform: ruby
11
11
  authors:
12
12
  - Florian Hanke
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2010-03-04 00:00:00 +01:00
20
+ date: 2010-04-15 00:00:00 +02:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency