pakyow-presenter 0.6.3.1 → 0.7.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.
@@ -2,22 +2,21 @@ module Pakyow
2
2
  module Presenter
3
3
  class Presenter < PresenterBase
4
4
  attr_accessor :current_context
5
-
5
+
6
+ def initialize
7
+ reset_state()
8
+ end
9
+
6
10
  #
7
11
  # Methods that are called by core. This is the interface that core expects a Presenter to have
8
12
  #
9
13
 
10
- def reload!
14
+ def load
11
15
  load_views
12
16
  end
13
-
14
- def present_for_request(request)
15
- @presented = false
16
- @root_path = nil
17
- @root_view_is_built = false
18
- @root_view = nil
19
- @view_path = nil
20
- @container_name = nil
17
+
18
+ def prepare_for_request(request)
19
+ reset_state()
21
20
  @request = request
22
21
  end
23
22
 
@@ -99,6 +98,25 @@ module Pakyow
99
98
  v
100
99
  end
101
100
 
101
+ # This is also for creating views from within a controller using the route based lookup mechanism.
102
+ # This method takes either a dir or file path and builds either a root_view or view, respectively.
103
+ def view_for_full_view_path(f_v_p, deep = false)
104
+ v = nil
105
+ real_path_info = @view_lookup_store.real_path_info(f_v_p)
106
+ if real_path_info
107
+ if real_path_info[:file_or_dir] == :file
108
+ v = View.new(real_path_info[:real_path])
109
+ elsif real_path_info[:file_or_dir] == :dir
110
+ root_view = @view_lookup_store.view_info(f_v_p)[:root_view]
111
+ v = View.new(root_view)
112
+ if v && deep
113
+ populate_view(v, @view_lookup_store.view_info(f_v_p)[:views])
114
+ end
115
+ end
116
+ end
117
+ v
118
+ end
119
+
102
120
  def populate_view_for_view_path(view, v_p)
103
121
  return view unless view_info = @view_lookup_store.view_info(v_p)
104
122
  views = view_info[:views]
@@ -124,27 +142,44 @@ module Pakyow
124
142
  #
125
143
  protected
126
144
  #
127
-
145
+
146
+ def reset_state
147
+ @presented = false
148
+ @root_path = nil
149
+ @root_view_is_built = false
150
+ @root_view = nil
151
+ @view_path = nil
152
+ @container_name = nil
153
+ end
154
+
128
155
  def build_root_view
129
156
  @root_view_is_built = true
130
157
 
131
158
  if @view_path
132
159
  v_p = @view_path
133
- elsif @request.restful
160
+ elsif @request && @request.restful
134
161
  v_p = restful_view_path(@request.restful)
135
- elsif @request.route_spec && @request.route_spec.index(':')
162
+ elsif @request && @request.route_spec && !@request.route_spec.is_a?(Regexp) && @request.route_spec.index(':')
136
163
  v_p = StringUtils.remove_route_vars(@request.route_spec)
137
164
  else
138
- v_p = @request.env['PATH_INFO']
165
+ v_p = @request && @request.working_path
139
166
  end
140
167
  return unless v_p
141
- return unless view_info = @view_lookup_store.view_info(v_p)
142
168
 
143
- @presented = true
144
- @root_path ||= view_info[:root_view]
145
- @root_view = LazyView.new(@root_path, true)
146
- views = view_info[:views]
147
- populate_view(self.view, views)
169
+ if Configuration::Base.presenter.view_caching
170
+ r_v = @populated_root_view_cache[v_p]
171
+ if r_v then
172
+ @root_view = r_v.dup
173
+ @presented = true
174
+ end
175
+ else
176
+ return unless view_info = @view_lookup_store.view_info(v_p)
177
+ @root_path ||= view_info[:root_view]
178
+ @root_view = LazyView.new(@root_path, true)
179
+ views = view_info[:views]
180
+ populate_view(self.view, views)
181
+ @presented = true
182
+ end
148
183
  end
149
184
 
150
185
  def restful_view_path(restful_info)
@@ -157,6 +192,19 @@ module Pakyow
157
192
 
158
193
  def load_views
159
194
  @view_lookup_store = ViewLookupStore.new("#{Configuration::Presenter.view_dir}")
195
+ if Configuration::Base.presenter.view_caching then
196
+ @populated_root_view_cache = build_root_view_cache(@view_lookup_store.view_info)
197
+ end
198
+ end
199
+
200
+ def build_root_view_cache(view_info)
201
+ r_v_c = {}
202
+ view_info.each{|dir,info|
203
+ r_v = LazyView.new(info[:root_view], true)
204
+ populate_view(r_v, info[:views])
205
+ r_v_c[dir] = r_v
206
+ }
207
+ r_v_c
160
208
  end
161
209
 
162
210
  # populates the top_view using view_store data by recursively building
@@ -168,7 +216,7 @@ module Pakyow
168
216
  path = views[name]
169
217
  if path
170
218
  v = populate_view(View.new(path), views)
171
- top_view.reset_container(name)
219
+ top_view.reset_container(name) # TODO revisit how this is implemented; assumes all LazyViews are root views
172
220
  top_view.add_content_to_container(v, name)
173
221
  end
174
222
  }
@@ -2,7 +2,7 @@ module Pakyow
2
2
  module Presenter
3
3
  class View
4
4
  class << self
5
- attr_accessor :binders, :cache, :default_view_path, :default_is_root_view
5
+ attr_accessor :binders, :default_view_path, :default_is_root_view
6
6
 
7
7
  def view_path(dvp, dirv=false)
8
8
  self.default_view_path = dvp
@@ -11,12 +11,16 @@ module Pakyow
11
11
  end
12
12
 
13
13
  attr_accessor :doc
14
-
14
+
15
+ def dup
16
+ self.class.new(@doc.dup)
17
+ end
18
+
15
19
  def initialize(arg=nil, is_root_view=false)
16
20
  arg = self.class.default_view_path if arg.nil? && self.class.default_view_path
17
21
  is_root_view = self.class.default_is_root_view if arg.nil? && self.class.default_is_root_view
18
22
 
19
- if arg.is_a?(Nokogiri::XML::Element)
23
+ if arg.is_a?(Nokogiri::XML::Element) || arg.is_a?(Nokogiri::XML::Document)
20
24
  @doc = arg
21
25
  elsif arg.is_a?(Pakyow::Presenter::Views)
22
26
  @doc = arg.first.doc.dup
@@ -28,18 +32,11 @@ module Pakyow
28
32
  else
29
33
  view_path = "#{Configuration::Presenter.view_dir}/#{arg}"
30
34
  end
31
- # Only load one time if view caching is enabled
32
- self.class.cache ||= {}
33
-
34
- if !self.class.cache.has_key?(view_path) || !Configuration::Base.presenter.view_caching
35
- if is_root_view then
36
- self.class.cache[view_path] = Nokogiri::HTML::Document.parse(File.read(view_path))
37
- else
38
- self.class.cache[view_path] = Nokogiri::HTML.fragment(File.read(view_path))
39
- end
35
+ if is_root_view then
36
+ @doc = Nokogiri::HTML::Document.parse(File.read(view_path))
37
+ else
38
+ @doc = Nokogiri::HTML.fragment(File.read(view_path))
40
39
  end
41
-
42
- @doc = self.class.cache[view_path].dup
43
40
  else
44
41
  raise ArgumentError, "No View for you! Come back, one year."
45
42
  end
@@ -91,8 +88,8 @@ module Pakyow
91
88
  ViewContext.new(self).instance_eval(&block)
92
89
  end
93
90
 
94
- def bind(object, type = nil)
95
- type = type || StringUtils.underscore(object.class.name)
91
+ def bind(object, opts = {})
92
+ bind_as = opts[:to] ? opts[:to].to_s : StringUtils.underscore(object.class.name.split('::').last)
96
93
 
97
94
  @doc.traverse do |o|
98
95
  if attribute = o.get_attribute('itemprop')
@@ -105,16 +102,10 @@ module Pakyow
105
102
 
106
103
  next unless attribute
107
104
 
108
- if selector.include?('[')
109
- type_len = type.length
110
- object_type = selector[0,type_len]
111
- attribute = selector[type_len + 1, attribute.length - type_len - 2]
112
- else
113
- object_type = nil
114
- attribute = selector
115
- end
105
+ type_len = bind_as.length
106
+ next if selector[0, type_len + 1] != "#{bind_as}["
116
107
 
117
- next if !object_type.nil? && object_type != type
108
+ attribute = selector[type_len + 1, attribute.length - type_len - 2]
118
109
 
119
110
  binding = {
120
111
  :element => o,
@@ -122,15 +113,15 @@ module Pakyow
122
113
  :selector => selector
123
114
  }
124
115
 
125
- bind_object_to_binding(object, binding, object_type.nil?)
116
+ bind_object_to_binding(object, binding, bind_as)
126
117
  end
127
118
  end
128
119
 
129
- def repeat_for(objects, &block)
120
+ def repeat_for(objects, opts = {}, &block)
130
121
  if o = @doc
131
122
  objects.each do |object|
132
123
  view = View.new(self)
133
- view.bind(object)
124
+ view.bind(object, opts)
134
125
  ViewContext.new(view).instance_exec(object, &block) if block_given?
135
126
 
136
127
  o.add_previous_sibling(view.doc)
@@ -239,23 +230,7 @@ module Pakyow
239
230
  end
240
231
 
241
232
  alias :render :append
242
-
243
- def +(value)
244
- if @previous_method
245
- append_value(val)
246
- else
247
- super
248
- end
249
- end
250
-
251
- def <<(value)
252
- if @previous_method
253
- append_value(val)
254
- else
255
- super
256
- end
257
- end
258
-
233
+
259
234
  def method_missing(method, *args)
260
235
  return unless @previous_method == :attributes
261
236
  @previous_method = nil
@@ -264,7 +239,15 @@ module Pakyow
264
239
  attribute = method.to_s.gsub('=', '')
265
240
  value = args[0]
266
241
 
267
- self.doc[attribute] = value
242
+ if value.is_a? Proc
243
+ value = value.call(self.doc[attribute])
244
+ end
245
+
246
+ if value.nil?
247
+ self.doc.remove_attribute(attribute)
248
+ else
249
+ self.doc[attribute] = value
250
+ end
268
251
  else
269
252
  return self.doc[method.to_s]
270
253
  end
@@ -298,32 +281,20 @@ module Pakyow
298
281
 
299
282
  protected
300
283
 
301
- def append_value(value_to_append)
302
- case @previous_method
303
- when :content
304
- append(value_to_append)
305
- end
306
-
307
- @previous_method = nil
308
- end
309
-
310
- def bind_object_to_binding(object, binding, wild = false)
284
+ def bind_object_to_binding(object, binding, bind_as)
311
285
  binder = nil
312
286
 
313
- # fetch value
314
- if object.is_a? Hash
315
- value = object[binding[:attribute]]
287
+ if View.binders
288
+ b = View.binders[bind_as.to_sym] and binder = b.new(object, binding[:element])
289
+ end
290
+
291
+ if binder && binder.class.method_defined?(binding[:attribute])
292
+ value = binder.send(binding[:attribute])
316
293
  else
317
- if View.binders
318
- b = View.binders[object.class.to_s.to_sym] and binder = b.new(object, binding[:element])
319
- end
320
-
321
- if binder && binder.class.method_defined?(binding[:attribute])
322
- value = binder.send(binding[:attribute])
294
+ if object.is_a? Hash
295
+ value = object[binding[:attribute]]
323
296
  else
324
- if wild && !object.class.method_defined?(binding[:attribute])
325
- return
326
- elsif Configuration::Base.app.dev_mode == true && !object.class.method_defined?(binding[:attribute])
297
+ if Configuration::Base.app.dev_mode == true && !object.class.method_defined?(binding[:attribute])
327
298
  Log.warn("Attempting to bind object to #{binding[:html_tag]}#{binding[:selector].gsub('*', '').gsub('\'', '')} but #{object.class.name}##{binding[:attribute]} is not defined.")
328
299
  return
329
300
  else
@@ -334,7 +305,13 @@ module Pakyow
334
305
 
335
306
  if value.is_a? Hash
336
307
  value.each do |k, v|
337
- if k == :content
308
+ if v.is_a? Proc
309
+ v = v.call(binding[:element][k.to_s])
310
+ end
311
+
312
+ if v.nil?
313
+ binding[:element].remove_attribute(k.to_s)
314
+ elsif k == :content
338
315
  bind_value_to_binding(v, binding, binder)
339
316
  else
340
317
  binding[:element][k.to_s] = v.to_s
@@ -382,7 +359,7 @@ module Pakyow
382
359
  binding[:element].inner_html = Nokogiri::HTML.fragment(value.to_s)
383
360
  end
384
361
  elsif binding[:element].name == 'input' && binding[:element][:type] == 'checkbox'
385
- if value == true || binding[:element].attributes['value'].value == value.to_s
362
+ if value == true || (binding[:element].attributes['value'] && binding[:element].attributes['value'].value == value.to_s)
386
363
  binding[:element]['checked'] = 'checked'
387
364
  else
388
365
  binding[:element].delete('checked')
@@ -21,8 +21,8 @@ module Pakyow
21
21
  # }
22
22
  # },
23
23
  # :abstract_paths => {
24
- # "/abstract/path/file.html" => "/abstract.root1/path/file.html",
25
- # "/some/other/path" => "/some/other.root1/path.root2"
24
+ # "/abstract/path/file.html" => {:real_path => "/abstract.root1/path/file.html", :file_or_dir => :file},
25
+ # "/some/other/path" => {:real_path => "/some/other.root1/path.root2", :file_or_dir => :dir}
26
26
  # }
27
27
  # }
28
28
  # This takes into account that a view directory may have a .root suffix.
@@ -46,11 +46,6 @@ module Pakyow
46
46
  default_views = {} # view_basename => path_to_view.html
47
47
  if File.exist?(view_dir) then
48
48
  default_root_view_file_path = "#{absolute_path_prefix}/#{Configuration::Presenter.default_view}"
49
- # See if the top level index directory overrides the default root view
50
- index_dirs = Dir.entries(view_dir).partition{|e| File.directory?("#{absolute_path_prefix}/#{e}") && e.start_with?('index.')}[0]
51
- if index_dirs.length == 1
52
- default_root_view_file_path = "#{absolute_path_prefix}/#{StringUtils.split_at_last_dot(index_dirs[0])[1]}.html"
53
- end
54
49
  # The logic depends on this traversing top down
55
50
  DirUtils.walk_dir(view_dir) { |vpath|
56
51
  if File.directory?(vpath)
@@ -89,9 +84,9 @@ module Pakyow
89
84
  else
90
85
  r_p = vpath.sub(absolute_path_prefix, '')
91
86
  end
92
- @view_store[:abstract_paths][route] = r_p
87
+ @view_store[:abstract_paths][route] = {:real_path => r_p, :file_or_dir => :dir}
93
88
  # duplicate real path under routes permuted with leading/trailing slash
94
- permute_route(route).each { |r| @view_store[:abstract_paths][r] = r_p } unless route == '/'
89
+ permute_route(route).each { |r| @view_store[:abstract_paths][r] = {:real_path => r_p, :file_or_dir => :dir} } unless route == '/'
95
90
  else
96
91
  # files here are direct overrides of the route's views
97
92
  parent,route = pakyow_path_to_route_and_parent(vpath, view_dir, :file)
@@ -108,13 +103,13 @@ module Pakyow
108
103
  # duplicating real path under route without the leading slash
109
104
  r_p = vpath.sub(absolute_path_prefix, '')
110
105
  if route == '/'
111
- @view_store[:abstract_paths]["/#{File.basename(vpath)}"] = r_p
112
- @view_store[:abstract_paths][File.basename(vpath)] = r_p
106
+ @view_store[:abstract_paths]["/#{File.basename(vpath)}"] = {:real_path => r_p, :file_or_dir => :file}
107
+ @view_store[:abstract_paths][File.basename(vpath)] = {:real_path => r_p, :file_or_dir => :file}
113
108
  else
114
109
  route_with_leading_slash = "#{route}/#{File.basename(vpath)}"
115
110
  route_without_leading_slash = route_with_leading_slash.sub('/','')
116
- @view_store[:abstract_paths][route_with_leading_slash] = r_p
117
- @view_store[:abstract_paths][route_without_leading_slash] = r_p
111
+ @view_store[:abstract_paths][route_with_leading_slash] = {:real_path => r_p, :file_or_dir => :file}
112
+ @view_store[:abstract_paths][route_without_leading_slash] = {:real_path => r_p, :file_or_dir => :file}
118
113
  end
119
114
  end
120
115
  }
@@ -162,9 +157,17 @@ module Pakyow
162
157
  return @view_store[:view_dirs]
163
158
  end
164
159
  end
160
+
161
+ def real_path_info(abstract_path = nil)
162
+ if abstract_path then
163
+ @view_store[:abstract_paths][abstract_path]
164
+ else
165
+ @view_store[:abstract_paths]
166
+ end
167
+ end
165
168
 
166
169
  def real_path(abstract_path)
167
- @view_store[:abstract_paths][abstract_path]
170
+ @view_store[:abstract_paths][abstract_path][:real_path] if @view_store[:abstract_paths][abstract_path]
168
171
  end
169
172
 
170
173
  private
@@ -200,7 +203,7 @@ module Pakyow
200
203
  end
201
204
 
202
205
  # Takes a route with a leading slash and no trailing slash (/route) and
203
- # returns the three other permutaions (/route/, route/, and route).
206
+ # returns the three other permutations (/route/, route/, and route).
204
207
  def permute_route(route0)
205
208
  route3 = route0.sub('/','')
206
209
  route2 = "#{route3}/"
@@ -65,16 +65,10 @@ module Pakyow
65
65
  end
66
66
 
67
67
  alias :render :append
68
-
69
- def +(val)
70
- self.each {|e| e + val}
71
- end
72
-
68
+
73
69
  def <<(val)
74
70
  if val.is_a? View
75
71
  @views << val
76
- else
77
- self.each {|e| e << val}
78
72
  end
79
73
  end
80
74
 
@@ -94,18 +88,18 @@ module Pakyow
94
88
  method_missing(:id)
95
89
  end
96
90
 
97
- def repeat_for(objects, &block)
91
+ def repeat_for(objects, opts = {}, &block)
98
92
  first_found = self.first
99
93
 
100
94
  # Remove other matches
101
95
  self.drop(1).each {|found| found.remove}
102
96
 
103
97
  # Repeat for first match
104
- first_found.repeat_for(objects, &block)
98
+ first_found.repeat_for(objects, opts, &block)
105
99
  end
106
100
 
107
- def bind(object)
108
- self.each {|e| e.bind(object)}
101
+ def bind(object, opts = {})
102
+ self.each {|e| e.bind(object, opts)}
109
103
  end
110
104
 
111
105
  def find(element)
metadata CHANGED
@@ -1,66 +1,56 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: pakyow-presenter
3
- version: !ruby/object:Gem::Version
4
- hash: 113
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 6
9
- - 3
10
- - 1
11
- version: 0.6.3.1
12
6
  platform: ruby
13
- authors:
7
+ authors:
14
8
  - Bryan Powell
15
9
  - Bret Young
16
10
  autorequire:
17
11
  bindir: bin
18
12
  cert_chain: []
19
-
20
- date: 2011-09-13 00:00:00 -05:00
21
- default_executable:
22
- dependencies:
23
- - !ruby/object:Gem::Dependency
13
+ date: 2011-11-19 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
24
16
  name: pakyow-core
25
- prerelease: false
26
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: &70363184265360 !ruby/object:Gem::Requirement
27
18
  none: false
28
- requirements:
29
- - - "="
30
- - !ruby/object:Gem::Version
31
- hash: 113
32
- segments:
33
- - 0
34
- - 6
35
- - 3
36
- - 1
37
- version: 0.6.3.1
19
+ requirements:
20
+ - - =
21
+ - !ruby/object:Gem::Version
22
+ version: 0.7.0
38
23
  type: :runtime
39
- version_requirements: *id001
40
- - !ruby/object:Gem::Dependency
41
- name: nokogiri
42
24
  prerelease: false
43
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: *70363184265360
26
+ - !ruby/object:Gem::Dependency
27
+ name: nokogiri
28
+ requirement: &70363184264680 !ruby/object:Gem::Requirement
44
29
  none: false
45
- requirements:
30
+ requirements:
46
31
  - - ~>
47
- - !ruby/object:Gem::Version
48
- hash: 5
49
- segments:
50
- - 1
51
- - 5
52
- version: "1.5"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
53
34
  type: :runtime
54
- version_requirements: *id002
35
+ prerelease: false
36
+ version_requirements: *70363184264680
37
+ - !ruby/object:Gem::Dependency
38
+ name: shoulda
39
+ requirement: &70363184263960 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: '2.11'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *70363184263960
55
48
  description: pakyow-presenter
56
49
  email: bryan@metabahn.com
57
50
  executables: []
58
-
59
51
  extensions: []
60
-
61
52
  extra_rdoc_files: []
62
-
63
- files:
53
+ files:
64
54
  - pakyow-presenter/CHANGES
65
55
  - pakyow-presenter/README
66
56
  - pakyow-presenter/MIT-LICENSE
@@ -76,41 +66,29 @@ files:
76
66
  - pakyow-presenter/lib/presenter/view_context.rb
77
67
  - pakyow-presenter/lib/presenter/view_lookup_store.rb
78
68
  - pakyow-presenter/lib/presenter/views.rb
79
- has_rdoc: true
80
69
  homepage: http://pakyow.com
81
70
  licenses: []
82
-
83
71
  post_install_message:
84
72
  rdoc_options: []
85
-
86
- require_paths:
73
+ require_paths:
87
74
  - pakyow-presenter/lib
88
- required_ruby_version: !ruby/object:Gem::Requirement
75
+ required_ruby_version: !ruby/object:Gem::Requirement
89
76
  none: false
90
- requirements:
91
- - - ">="
92
- - !ruby/object:Gem::Version
93
- hash: 57
94
- segments:
95
- - 1
96
- - 8
97
- - 7
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
98
80
  version: 1.8.7
99
- required_rubygems_version: !ruby/object:Gem::Requirement
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
82
  none: false
101
- requirements:
102
- - - ">="
103
- - !ruby/object:Gem::Version
104
- hash: 3
105
- segments:
106
- - 0
107
- version: "0"
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
108
87
  requirements: []
109
-
110
88
  rubyforge_project: pakyow-presenter
111
- rubygems_version: 1.6.2
89
+ rubygems_version: 1.8.10
112
90
  signing_key:
113
91
  specification_version: 3
114
92
  summary: pakyow-presenter
115
93
  test_files: []
116
-
94
+ has_rdoc: