representations 0.0.2 → 0.0.3

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.markdown CHANGED
@@ -1,10 +1,10 @@
1
- # Resouce Representations
1
+ # Representations
2
2
 
3
3
  Rails helpers, including form builders are great to allow rapid development of applications and views.
4
4
 
5
5
  They are procedural in nature and have hard time to adapt to complex models. They also live in a single namespace making it difficult to find which helpers apply to which models.
6
6
 
7
- Resource representations change syntax to object oriented and model specific.
7
+ Representations change syntax to object oriented and model specific.
8
8
 
9
9
  ## Example usage
10
10
 
@@ -27,7 +27,7 @@ Rails helpers:
27
27
  = f.label(:eye_color_blue, "Blue")
28
28
  = f.submit("Submit")
29
29
 
30
- Resource Representations
30
+ Representations:
31
31
 
32
32
  - r(user).form do
33
33
  login:
@@ -42,10 +42,24 @@ Resource Representations
42
42
  = p.last_name.text_field
43
43
  = p.eye_color.radio_button('blue')
44
44
  = p.eye_color.radio_button_label('blue', 'Blue')
45
- ###Extensions
45
+ ##Extensions
46
46
  Representations can be altered. For example to add new method DefaultRepresentation create file app/representations/default_representation.rb with the content:
47
- module DefaultRepresentation
48
- def new_method
49
- some code
50
- end
51
- end
47
+ module DefaultRepresentation
48
+ def new_method
49
+ some code
50
+ end
51
+ end
52
+ ##Nested attributes
53
+ - user.children.each do |child|
54
+ = child.name.label
55
+ = child.name.text_field
56
+ = child.delete_checkbox
57
+ = child.delete_checkbox_label
58
+ Or even:
59
+ - user.children.build do |child|
60
+ = child.name.label
61
+ = child.name.text_field
62
+ ## Automatic wrapping
63
+ Create file config/initializers/representations.rb
64
+ Representations.enable_automatic_wrapping = true
65
+ if you want Representations to automatically wrap variables from the controller
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.3
data/init.rb CHANGED
@@ -2,3 +2,4 @@ require 'view_helpers'
2
2
  require 'representations'
3
3
  ActionView::Base.send :include, Representations::ViewHelpers
4
4
  ActiveSupport::Dependencies.load_paths << "#{RAILS_ROOT}/app/representations/"
5
+
@@ -1,33 +1,48 @@
1
1
  module Representations
2
+ #Enables automatic wrapping
3
+ #TODO should be disabled until module unloading will be fixed
4
+ def self.enable_automatic_wrapping=(value)
5
+ if value
6
+ ActionView::Base.class_eval do
7
+ def instance_variable_set_with_r(symbol, obj)
8
+ load ActiveSupport::Dependencies.search_for_file('representations.rb')
9
+ obj = Representations.representation_for(obj, self, symbol.to_s[1..-1]) if obj.is_a?(ActiveRecord::Base)
10
+ instance_variable_set_without_r(symbol, obj) #call to the original method
11
+ end
12
+ self.alias_method_chain :instance_variable_set, :r
13
+ end
14
+ end
15
+ end
2
16
  #Creates Representation for object passed as a paremeter, type of the representation
3
17
  #depends on the type of the object
4
18
  def representation_for(object, template, name=nil, parent=nil)
5
- representation_class = if object.is_a?(ActiveRecord::Base)
6
- ActiveRecordRepresentation
7
- else
8
- "Representations::#{object.class.to_s.demodulize}Representation".constantize rescue DefaultRepresentation
9
- end
19
+ representation_class =
20
+ begin
21
+ if object.is_a?(ActiveRecord::Base)
22
+ ActiveRecordRepresentation
23
+ else
24
+ "Representations::#{object.class.to_s.demodulize}Representation".constantize
25
+ end
26
+ rescue
27
+ AssociationsRepresentation if object.ancestors.include?(ActiveRecord::Associations) rescue DefaultRepresentation
28
+ end
10
29
  representation_class.new(object, template, name, parent)
11
30
  end
12
31
 
13
32
  module_function :representation_for
14
-
15
33
  class Representation
16
34
 
17
35
  #value - object for which the representation is created
18
- #template - template view
36
+ #template - template view (needed because some ActionView::Base methods are private)
19
37
  #name - the actuall name of the method that was called on the object's parent that is being initialize
38
+ #parent - Representation object which contains the object that is being initialize
20
39
  def initialize(value, template, name=nil, parent=nil)
21
40
  @value = value
22
41
  @name = name
23
42
  @template = template
24
43
  @parent = parent
25
- begin #extend class if user provided file for customisation
26
- self.send(:extend, "::#{self.class.to_s.demodulize}".constantize)
27
- rescue
28
- puts "::#{self.class.to_s.demodulize} not defined"
29
- #procced then (user did not provide file for customisation of the class)
30
- end
44
+ #extend class if user provided appropriate file (look at the files app/representations/*_representation.rb)
45
+ self.send(:extend, "::#{self.class.to_s.demodulize}".constantize) rescue Rails.logger.info "No extension defined for ::#{self.class.to_s}"
31
46
  end
32
47
 
33
48
  def id
@@ -40,7 +55,7 @@ module Representations
40
55
  #returns html label tag for the representation
41
56
  def label(value = nil, html_options = {})
42
57
  tree = get_parents_tree
43
- for_attr_value = tree.join('_')
58
+ for_attr_value = tree.collect{ |x| x[0] }.join('_')
44
59
  tags = get_tags(html_options, {:for => for_attr_value})
45
60
  value = ERB::Util::h(@name.humanize) if value.nil?
46
61
  %Q{<label #{tags}>#{value}</label>}
@@ -51,31 +66,40 @@ module Representations
51
66
  def with_block(&block)
52
67
  yield self if block_given?
53
68
  end
54
- #Returns array of Represantation objects which are linked together by @parent field
69
+ #Returns two dimensional array based on the tree of the Represantation objects which are linked together by the @parent field
70
+ #First element of the array consists of Representation's @name and the second of Representation's class
55
71
  def get_parents_tree
56
- children_names = Array.new
72
+ tree = Array.new
73
+ tree[0] = []
74
+ tree[0][0] = @name
75
+ tree[0][1] = self.class
57
76
  parent = @parent
58
- children_names.push(@name)
59
- while parent.nil? == false do #iterate parent tree
60
- children_names.push(parent.instance_variable_get(:@name))
77
+ while parent do #iterate parent tree
78
+ array = []
79
+ array[0] = parent.instance_variable_get(:@name)
80
+ array[1] = parent.class
81
+ tree.unshift(array)
61
82
  parent = parent.instance_variable_get(:@parent)
62
- end #children_names now looks something like that [name, profile, user]
63
- children_names.reverse!
83
+ end
84
+ tree #tree now looks something like this [['user', ActiverRecordRepresentation], ['nick', DefaultRepresentation]]
64
85
  end
65
- #Creates value of the html name attribute according to passed tree of objects
86
+ #Creates value of the html name attribute according to the passed tree
66
87
  def get_html_name_attribute_value(tree)
67
- root_name = tree.delete_at(0)
68
- name = Array.new
69
- tree.each_index do |idx|
70
- name[idx] = if idx < tree.length - 1
71
- "[" + tree[idx] + "_attributes]"
72
- else
73
- "[" + tree[idx] + "]"
74
- end
88
+ first = tree.delete_at(0)
89
+ root_name = first[0]
90
+ name = []
91
+ prev = nil
92
+ tree.each do |elem|
93
+ if elem[1] == DefaultRepresentation || elem[1] == TimeWithZoneRepresentation || prev == AssociationsRepresentation
94
+ name.push "[" + elem[0] + "]"
95
+ else
96
+ name.push "[" + elem[0] + "_attributes]"
97
+ end
98
+ prev = elem[1]
75
99
  end
76
100
  name.unshift(root_name)
77
101
  end
78
- #Returns string created by merging two hashes of html options passed as an argument
102
+ #Returns string created by merging two hashes of html options passed as the arguments
79
103
  def get_tags(user_options, base_options)
80
104
  options = base_options.merge(user_options)
81
105
  options.stringify_keys!
@@ -85,14 +109,11 @@ module Representations
85
109
  end
86
110
 
87
111
  class DefaultRepresentation < Representation
88
- #require_dependency "#{RAILS_ROOT}/app/representations/default_representation"
89
- #require "#{RAILS_ROOT}/app/representations/default_representation"
90
- #include DefaultRepresentationExt
91
112
  #not tested in the view
92
113
  #Returns string with html check box tag
93
114
  def check_box(checked_value = "1", unchecked_value = "0", html_options = {})
94
115
  tree = get_parents_tree
95
- id_attr_value = tree.join('_')
116
+ id_attr_value = tree.collect{ |x| x[0] }.join('_')
96
117
  name_attr_value = get_html_name_attribute_value(tree)
97
118
  tags = get_tags(html_options, {:value => checked_value, :id => id_attr_value, :name=>name_attr_value})
98
119
  %Q{<input type="checkbox" #{tags}/>\n<input type="hidden" value="#{unchecked_value}" id="#{id_attr_value}" name="#{name_attr_value}"/>}
@@ -101,7 +122,7 @@ module Representations
101
122
  #Returns string with html file field tag
102
123
  def file_field(html_options = {})
103
124
  tree = get_parents_tree
104
- id_attr_value = tree.join('_')
125
+ id_attr_value = tree.collect{ |x| x[0] }.join('_')
105
126
  tags = get_tags(html_options, {:value => to_s, :id => id_attr_value, :name=>get_html_name_attribute_value(tree)})
106
127
  %Q{<input type="file" #{tags}/>}
107
128
  end
@@ -109,36 +130,35 @@ module Representations
109
130
  #Returns string with html hidden input tag
110
131
  def hidden_field(html_options = {})
111
132
  tree = get_parents_tree
112
- id_attr_value = tree.join('_')
133
+ id_attr_value = tree.collect{ |x| x[0] }.join('_')
113
134
  tags = get_tags(html_options, {:value => to_s, :id => id_attr_value, :name=>get_html_name_attribute_value(tree)})
114
135
  %Q{<input type="hidden" #{tags}/>}
115
136
  end
116
137
  #Returns string with html text input tag
117
138
  def text_field(html_options = {})
118
- puts "#{RAILS_ROOT}/app/representations/default_representation"
119
139
  tree = get_parents_tree
120
- id_attr_value = tree.join('_')
140
+ id_attr_value = tree.collect{ |x| x[0] }.join('_')
121
141
  tags = get_tags(html_options, {:value => to_s, :id => id_attr_value, :name=>get_html_name_attribute_value(tree)})
122
142
  %Q{<input type="text" #{tags}/>}
123
143
  end
124
144
  #Returns string with html text area tag
125
145
  def text_area(html_options = {})
126
146
  tree = get_parents_tree
127
- id_attr_value = tree.join('_')
147
+ id_attr_value = tree.collect{ |x| x[0] }.join('_')
128
148
  tags = get_tags(html_options, {:id => id_attr_value, :name => get_html_name_attribute_value(tree)})
129
149
  %Q{<textarea #{tags}>\n#{to_s}\n</textarea>}
130
150
  end
131
151
  #Returns string with html password tag
132
152
  def password_field(html_options = {})
133
153
  tree = get_parents_tree
134
- id_attr_value = tree.join('_')
154
+ id_attr_value = tree.collect{ |x| x[0] }.join('_')
135
155
  tags = get_tags(html_options, {:value => to_s, :id => id_attr_value, :name=>get_html_name_attribute_value(tree)})
136
156
  %Q{<input type="password" #{tags}/>}
137
157
  end
138
158
  #Returns string with html radio button tag
139
159
  def radio_button(value, html_options = {})
140
160
  tree = get_parents_tree
141
- id_attr_value = tree.join('_') + "_#{value}"
161
+ id_attr_value = tree.collect{ |x| x[0] }.join('_') + "_#{value}"
142
162
  name_attr_value = get_html_name_attribute_value(tree)
143
163
  tags = get_tags(html_options, {:name => name_attr_value, :value=>value, :id=>id_attr_value, :checked=>"#{@value.capitalize==value.capitalize}"})
144
164
  %Q{<input type="radio" #{tags}/>}
@@ -146,68 +166,115 @@ module Representations
146
166
  #Returns string with html label tag with for attribute set to the radio button of this object
147
167
  def radio_button_label(radio_button_value, value = nil, html_options = {})
148
168
  tree = get_parents_tree
149
- for_attr_value = tree.join('_') + "_#{radio_button_value}"
169
+ for_attr_value = tree.collect{ |x| x[0] }.join('_') + "_#{radio_button_value}"
150
170
  value = radio_button_value.capitalize if value.nil?
151
171
  tags = get_tags(html_options, {:for => for_attr_value})
152
172
  %Q{<label #{tags}>#{ERB::Util::h(value)}</label>}
153
173
  end
174
+ end
175
+ #Representation for objects which are nil
176
+ class NilClassRepresentation < Representation
177
+ #Returns self so the calls:
178
+ #nil_object.not_defined_method.another_not_defined_method
179
+ #want raise an error
180
+ def method_missing(method_name, *args)
181
+ return self
154
182
  end
155
- #Representation for objects which are nil
156
- class NilClassRepresentation < Representation
157
- #Returns self so the calls:
158
- #nil_object.not_defined_method.another_not_defined_method
159
- #want raise an error
160
- def method_missing(method_name, *args)
161
- return self
162
- end
163
- #Passed block shouldn't be called
164
- def with_block(&block)
165
- end
166
- #Returns blank string
167
- def to_s
168
- return ''
169
- end
183
+ #Passed block shouldn't be called
184
+ def with_block(&block)
170
185
  end
171
- #Representation for ActiveRecord::Base object's
172
- class ActiveRecordRepresentation < Representation
173
- #Form builder
174
- def form(&block)
175
- raise "You need to provide block to form representation" unless block_given?
176
- content = @template.capture(self, &block)
177
- @template.concat(@template.form_tag(@value))
178
- @template.concat(content)
179
- @template.concat("</form>")
180
- self
181
- end
182
- #Forwards ActiveRecord invocation and wraps result in apropriate Representation
183
- #Suppose that User extends ActiveRecord::Base :
184
- #ar_user = User.new
185
- #ar_user.nick = 'foo'
186
- #user = r(ar_user) #user is now ActiveRecordRepresentation
187
- #user.nick.text_field #method_missing will be called on user with method_name = 'nick' in which new method for user will be created and will be called. The newly created method will create a new DefaultRepresentation with @value set to the string 'foo'. Next the text_field will be called on the newly created DefauleRepresentation
188
- #
189
- def method_missing(method_name, *args, &block)
190
- method = <<-EOF
186
+ #Returns blank string
187
+ def to_s
188
+ return ''
189
+ end
190
+ end
191
+ #Representation for ActiveRecord::Base object's
192
+ class ActiveRecordRepresentation < Representation
193
+ #Form builder
194
+ def form(&block)
195
+ raise "You need to provide block to form representation" unless block_given?
196
+ content = @template.capture(self, &block)
197
+ @template.concat(@template.form_tag(@value))
198
+ @template.concat(content)
199
+ @template.concat("</form>")
200
+ self
201
+ end
202
+ #Forwards ActiveRecord invocation and wraps result in appropriate Representation
203
+ #Suppose that User extends ActiveRecord::Base :
204
+ #ar_user = User.new
205
+ #ar_user.nick = 'foo'
206
+ #user = r(ar_user) #user is now ActiveRecordRepresentation
207
+ #user.nick.text_field #method_missing will be called on user with method_name = 'nick' in which new method for user will be created and will be called. The newly created method will create a new DefaultRepresentation with @value set to the string 'foo'. Next the text_field will be called on the newly created DefaultRepresentation
208
+ def method_missing(method_name, *args, &block)
209
+ method = <<-EOF
191
210
  def #{method_name}(*args, &block)
192
211
  @__#{method_name} ||= Representations.representation_for(@value.#{method_name}, @template, "#{method_name}", self)
193
212
  @__#{method_name}.with_block(&block)
194
213
  @__#{method_name} if block.nil?
195
214
  end
196
- EOF
197
- ::Representations::ActiveRecordRepresentation.class_eval(method, __FILE__, __LINE__)
198
-
199
- self.__send__(method_name, &block)
215
+ EOF
216
+ ::Representations::ActiveRecordRepresentation.class_eval(method, __FILE__, __LINE__)
217
+ self.__send__(method_name, &block)
218
+ end
219
+ end
220
+ #Representation for TimeWithZone object
221
+ class TimeWithZoneRepresentation < Representation
222
+ def select(passed_options = {}, html_options = {})
223
+ options = {:defaults => {:day => @value.day, :month => @value.month, :year => @value.year}}
224
+ options.merge!(passed_options)
225
+ tree = get_parents_tree
226
+ name = get_html_name_attribute_value(tree)
227
+ @template.date_select(name, @name, options, html_options)
228
+ end
229
+ end
230
+ #Representation for Collections
231
+ class AssociationsRepresentation < Representation
232
+ #initilize @num variable
233
+ def initialize(object, template, name, parent)
234
+ super
235
+ @num = 0
236
+ end
237
+ #Creates Representation for every object in the Array and invokes passed block with this Representation as the argument
238
+ def each
239
+ @value.each do |object|
240
+ representation_object = Representations.representation_for(object, @template, object.id.to_s, self)
241
+ yield representation_object
200
242
  end
201
243
  end
202
- #Representation for TimeWithZone object
203
- class TimeWithZoneRepresentation < Representation
204
- def select(passed_options = {}, html_options = {})
205
- options = {:defaults => {:day => @value.day, :month => @value.month, :year => @value.year}}
206
- options.merge!(passed_options)
207
- tree = get_parents_tree
208
- tree.pop
209
- name = get_html_name_attribute_value(tree)
210
- @template.date_select(name, @name, options, html_options)
244
+ #Creates new object in the collection and input fields for it defined in the passed block
245
+ def build
246
+ new_object = @value.build
247
+ representation_object = AssociationsRepresentation::NewRecordRepresentation.new(new_object, @template, 'new_' + num.to_s, self)
248
+ yield representation_object
249
+ end
250
+ private
251
+ attr_reader :num
252
+ #Used for generating unique @name for ArrayRepresentation::NewRecordRepresentation
253
+ def num
254
+ @num += 1
255
+ end
256
+ #Representation that wraps newly created ActiveRecord::Base that will be added to some collection
257
+ class NewRecordRepresentation < Representation
258
+ #Creates new method which wraps call for ActionRecord
259
+ #New method returns Representation which represents datatype in the appropriate column
260
+ def method_missing(method_name_symbol, *args, &block)
261
+ method_name = method_name_symbol.to_s
262
+ representation_class = case @value.class.columns_hash[method_name].type
263
+ when :string
264
+ "DefaultRepresentation"
265
+ when :date
266
+ "TimeWithZoneRepresentation"
267
+ end
268
+ method = <<-EOF
269
+ def #{method_name}(*args, &block)
270
+ @__#{method_name} ||= #{representation_class}.new(@value.#{method_name}, @template, "#{method_name}", self)
271
+ @__#{method_name}.with_block(&block)
272
+ @__#{method_name} if block.nil?
273
+ end
274
+ EOF
275
+ ::Representations::AssociationsRepresentation::NewRecordRepresentation.class_eval(method, __FILE__, __LINE__)
276
+ self.__send__(method_name_symbol, &block)
211
277
  end
212
278
  end
213
279
  end
280
+ end
data/lib/view_helpers.rb CHANGED
@@ -1,9 +1,15 @@
1
1
  module Representations
2
2
  module ViewHelpers
3
3
  def r(model)
4
- r = Representations.representation_for(model, self, model.class.to_s.downcase)
4
+ r = Representations.representation_for(model, self, find_variables_name(model))
5
5
  yield r if block_given?
6
6
  r
7
7
  end
8
+ private
9
+ def find_variables_name(object)
10
+ self.instance_variables.each do |name|
11
+ return name[1..-1] if instance_variable_get(name) == object
12
+ end
13
+ end
8
14
  end
9
15
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{representations}
8
- s.version = "0.0.2"
8
+ s.version = "0.0.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["\305\201ukasz Piestrzeniewicz", "Adam Sokolnicki"]
12
- s.date = %q{2009-10-20}
12
+ s.date = %q{2009-10-24}
13
13
  s.description = %q{Rails helpers, including form builders are great to allow rapid development of applications and views.
14
14
  They are procedural in nature and have hard time to adapt to complex models. They also live in a single namespace making it difficult to find which helpers apply to which models.
15
15
  Resource representations change syntax to object oriented and model specific.}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: representations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - "\xC5\x81ukasz Piestrzeniewicz"
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-10-20 00:00:00 +02:00
13
+ date: 2009-10-24 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies: []
16
16