pakyow-presenter 0.8.0 → 0.9.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.
- checksums.yaml +4 -4
- data/pakyow-presenter/CHANGES +11 -1
- data/pakyow-presenter/lib/presenter/attributes.rb +18 -15
- data/pakyow-presenter/lib/presenter/base.rb +8 -2
- data/pakyow-presenter/lib/presenter/binder.rb +53 -43
- data/pakyow-presenter/lib/presenter/binder_set.rb +18 -27
- data/pakyow-presenter/lib/presenter/binding_eval.rb +23 -0
- data/pakyow-presenter/lib/presenter/config/presenter.rb +36 -61
- data/pakyow-presenter/lib/presenter/doc_helpers.rb +6 -66
- data/pakyow-presenter/lib/presenter/helpers.rb +26 -3
- data/pakyow-presenter/lib/presenter/nokogiri_doc.rb +321 -0
- data/pakyow-presenter/lib/presenter/page.rb +5 -14
- data/pakyow-presenter/lib/presenter/presenter.rb +14 -13
- data/pakyow-presenter/lib/presenter/string_doc.rb +287 -0
- data/pakyow-presenter/lib/presenter/string_doc_parser.rb +124 -0
- data/pakyow-presenter/lib/presenter/string_doc_renderer.rb +18 -0
- data/pakyow-presenter/lib/presenter/template.rb +13 -37
- data/pakyow-presenter/lib/presenter/view.rb +192 -424
- data/pakyow-presenter/lib/presenter/view_collection.rb +70 -112
- data/pakyow-presenter/lib/presenter/view_composer.rb +2 -47
- data/pakyow-presenter/lib/presenter/view_context.rb +89 -0
- data/pakyow-presenter/lib/presenter/view_store.rb +12 -12
- metadata +30 -10
- data/pakyow-presenter/lib/presenter/title_helpers.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3b7aee6ee2692ce29bd4e2bdaa323fae1aedef3
|
4
|
+
data.tar.gz: 1e743f0597314c2a52fcc32a2c4f490b62eb1db8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd7aa6575f476fe52a680d9b7fe0a4465337556323b1bdc03ff0997aa6f6bbc8fdd71b3137b678c1239d626b3bd5b002f28fc81cbe9ce0a56ba6dc38137e48df
|
7
|
+
data.tar.gz: 1d0e79dcdd3c8910cd6af4f76906bd1b26575f33e83759dae61414766b55c0ba26d7e1380939f5a0bfb885de9c160572984623b62b112d6083e2210e5b0e7a13
|
data/pakyow-presenter/CHANGES
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
= 0.9.0
|
2
|
+
|
3
|
+
* Introduces StringDoc, replacing Nokogiri for view rendering with a performant alternative
|
4
|
+
* Adds the ability to set an empty first option in bindings
|
5
|
+
* Remove the annoying "no content" for container log message
|
6
|
+
* Binding context must now be explicitly passed when binding
|
7
|
+
* Yield bindable value before bindable in view binding fns
|
8
|
+
* Fixes bug causing non-html view contents to be processed twice
|
9
|
+
* Removes support for Ruby versions < 2.0.0
|
10
|
+
|
1
11
|
= 0.8.0 / 2014-03-02
|
2
12
|
|
3
13
|
* Major rewrite, including new view syntax, composer, and transformation api
|
@@ -38,4 +48,4 @@
|
|
38
48
|
|
39
49
|
= 0.6.0 / 2011-08-20
|
40
50
|
|
41
|
-
* Initial gem release of 0.6.0 codebase
|
51
|
+
* Initial gem release of 0.6.0 codebase
|
@@ -53,14 +53,13 @@ module Pakyow
|
|
53
53
|
def method_missing(method, *args)
|
54
54
|
ret = @value.send(method, *args)
|
55
55
|
update_value
|
56
|
-
|
57
56
|
return ret
|
58
57
|
end
|
59
58
|
|
60
59
|
# returns the full string value
|
61
60
|
def to_s
|
62
61
|
value = @value
|
63
|
-
value = value.call(deconstruct_attribute_value_of_type(@doc
|
62
|
+
value = value.call(deconstruct_attribute_value_of_type(@doc.get_attribute(@name), @type)) if value.is_a? Proc
|
64
63
|
value = construct_attribute_value_of_type(value, @type, @name)
|
65
64
|
|
66
65
|
return value
|
@@ -70,6 +69,10 @@ module Pakyow
|
|
70
69
|
@value
|
71
70
|
end
|
72
71
|
|
72
|
+
def ancestors
|
73
|
+
self.class.ancestors
|
74
|
+
end
|
75
|
+
|
73
76
|
private
|
74
77
|
|
75
78
|
def update_value
|
@@ -117,10 +120,9 @@ module Pakyow
|
|
117
120
|
end
|
118
121
|
|
119
122
|
class Attributes
|
120
|
-
def initialize(doc
|
123
|
+
def initialize(doc)
|
121
124
|
@doc = doc
|
122
125
|
@attributes = {}
|
123
|
-
@composer = composer
|
124
126
|
end
|
125
127
|
|
126
128
|
def method_missing(method, *args)
|
@@ -144,34 +146,28 @@ module Pakyow
|
|
144
146
|
def class(*args)
|
145
147
|
method_missing(:class, *args)
|
146
148
|
end
|
147
|
-
|
149
|
+
|
148
150
|
def id(*args)
|
149
151
|
method_missing(:id, *args)
|
150
152
|
end
|
151
153
|
|
152
154
|
def update_value_for_attribute(attribute, value)
|
153
|
-
|
154
|
-
@doc.children.first[attribute] = value
|
155
|
-
else
|
156
|
-
@doc[attribute] = value
|
157
|
-
end
|
155
|
+
@doc.update_attribute(attribute, value)
|
158
156
|
end
|
159
157
|
|
160
158
|
def remove_attribute(attribute)
|
161
159
|
@doc.remove_attribute(attribute)
|
162
|
-
@composer.dirty! unless @composer.nil?
|
163
160
|
end
|
164
161
|
|
165
162
|
protected
|
166
163
|
|
167
164
|
def set_attribute(attribute, value)
|
168
165
|
get_attribute(attribute).set(value)
|
169
|
-
@composer.dirty! unless @composer.nil?
|
170
166
|
end
|
171
167
|
|
172
168
|
def get_attribute(attribute)
|
173
169
|
unless a = @attributes[attribute]
|
174
|
-
a = Attribute.new(attribute, @doc
|
170
|
+
a = Attribute.new(attribute, @doc.get_attribute(attribute), self, @doc)
|
175
171
|
end
|
176
172
|
|
177
173
|
return a
|
@@ -187,10 +183,17 @@ module Pakyow
|
|
187
183
|
|
188
184
|
def <<(attributes)
|
189
185
|
@attributes << attributes
|
186
|
+
self
|
187
|
+
end
|
188
|
+
|
189
|
+
def each
|
190
|
+
@attributes.each { |a| yield(a) }
|
190
191
|
end
|
191
192
|
|
192
193
|
def method_missing(method, *args)
|
193
|
-
@attributes.inject(AttributesCollection.new) { |coll, a|
|
194
|
+
@attributes.inject(AttributesCollection.new) { |coll, a|
|
195
|
+
coll << a.send(method, *args)
|
196
|
+
}
|
194
197
|
end
|
195
198
|
|
196
199
|
def to_s
|
@@ -200,7 +203,7 @@ module Pakyow
|
|
200
203
|
def class(*args)
|
201
204
|
method_missing(:class, *args)
|
202
205
|
end
|
203
|
-
|
206
|
+
|
204
207
|
def id(*args)
|
205
208
|
method_missing(:id, *args)
|
206
209
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
|
2
3
|
require 'presenter/view_store'
|
3
|
-
require 'presenter/doc_helpers'
|
4
|
-
require 'presenter/title_helpers'
|
5
4
|
require 'presenter/view'
|
6
5
|
require 'presenter/template'
|
7
6
|
require 'presenter/page'
|
@@ -13,6 +12,13 @@ require 'presenter/binder_set'
|
|
13
12
|
require 'presenter/attributes'
|
14
13
|
require 'presenter/exceptions'
|
15
14
|
require 'presenter/view_composer'
|
15
|
+
require 'presenter/nokogiri_doc'
|
16
|
+
require 'presenter/string_doc'
|
17
|
+
require 'presenter/string_doc_parser'
|
18
|
+
require 'presenter/string_doc_renderer'
|
19
|
+
require 'presenter/binding_eval'
|
20
|
+
require 'presenter/doc_helpers'
|
21
|
+
require 'presenter/view_context'
|
16
22
|
|
17
23
|
module Pakyow
|
18
24
|
module Presenter
|
@@ -1,78 +1,88 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
1
3
|
module Pakyow
|
2
4
|
module Presenter
|
3
|
-
# A singleton that manages
|
5
|
+
# A singleton that manages BinderSet instances for an app. It handles
|
6
|
+
# the creation / registration of sets and provides a mechanism
|
7
|
+
# to augment data to be bound with values from the sets.
|
4
8
|
#
|
5
9
|
class Binder
|
6
10
|
include Singleton
|
7
|
-
include Helpers
|
8
11
|
|
12
|
+
# Access to the registered binder sets for an app.
|
13
|
+
#
|
9
14
|
attr_reader :sets
|
10
15
|
|
11
16
|
def initialize
|
12
17
|
@sets = {}
|
13
18
|
end
|
14
19
|
|
15
|
-
#
|
20
|
+
# Resets the registered binder sets.
|
21
|
+
#
|
22
|
+
# @return [Binder] the reset instance
|
23
|
+
#
|
16
24
|
def reset
|
17
25
|
@sets = {}
|
18
26
|
self
|
19
27
|
end
|
20
28
|
|
21
|
-
# Creates a new set.
|
29
|
+
# Creates and registers a new binder set by name. A block should be passed
|
30
|
+
# that defines the bindings. This block will be evaluated in context
|
31
|
+
# of the created binder set.
|
32
|
+
#
|
33
|
+
# @see BinderSet
|
34
|
+
#
|
35
|
+
# @param name [Symbol] the name of the binder set to be created
|
22
36
|
#
|
23
37
|
def set(name, &block)
|
24
|
-
@sets[name] = BinderSet.new
|
25
|
-
@sets[name].instance_exec(&block)
|
38
|
+
@sets[name] = BinderSet.new(&block)
|
26
39
|
end
|
27
40
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
41
|
+
# Returns the value for the scope->prop by applying any defined bindings to the data.
|
42
|
+
#
|
43
|
+
# @param scope [Symbol] the scope name
|
44
|
+
# @param prop [Symbol] the prop name
|
45
|
+
# @param bindable [Symbol] the data being bound
|
46
|
+
# @param bindings [Symbol] additional bindings to take into consideration when determining the value
|
47
|
+
# @param context [Symbol] context passed through to the defined bindings
|
48
|
+
#
|
49
|
+
def value_for_scoped_prop(scope, prop, bindable, bindings, context)
|
50
|
+
binding_fn = @sets.lazy.map { |set|
|
51
|
+
set[1].match_for_prop(prop, scope, bindable, bindings)
|
52
|
+
}.find { |match|
|
53
|
+
!match.nil?
|
34
54
|
}
|
35
55
|
|
36
|
-
if
|
56
|
+
if binding_fn
|
37
57
|
binding_eval = BindingEval.new(prop, bindable, context)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
when 2
|
45
|
-
self.instance_exec(bindable, binding_eval.value, &binding)
|
58
|
+
binding_eval.instance_exec(binding_eval.value, bindable, context, &binding_fn)
|
59
|
+
else # default value
|
60
|
+
if bindable.is_a?(Hash)
|
61
|
+
bindable[prop]
|
62
|
+
elsif bindable.class.method_defined?(prop)
|
63
|
+
bindable.send(prop)
|
46
64
|
end
|
47
|
-
else
|
48
|
-
# default
|
49
|
-
prop_value_for_bindable(bindable, prop)
|
50
65
|
end
|
51
66
|
end
|
52
67
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@sets.each {|set|
|
61
|
-
match = set[1].options_for_prop(*args)
|
62
|
-
break if match
|
68
|
+
# Returns true if a binding is defined for the scope->prop.
|
69
|
+
#
|
70
|
+
def has_scoped_prop?(scope, prop, bindings)
|
71
|
+
@sets.lazy.map { |set|
|
72
|
+
set[1].has_prop?(scope, prop, bindings)
|
73
|
+
}.find { |has_prop|
|
74
|
+
has_prop
|
63
75
|
}
|
64
|
-
|
65
|
-
return match
|
66
76
|
end
|
67
77
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
78
|
+
# Returns options for the scope->prop.
|
79
|
+
#
|
80
|
+
def options_for_scoped_prop(scope, prop, bindable, context)
|
81
|
+
@sets.lazy.map { |set|
|
82
|
+
set[1].options_for_prop(scope, prop, bindable, context)
|
83
|
+
}.find { |options|
|
84
|
+
!options.nil?
|
73
85
|
}
|
74
|
-
|
75
|
-
return has
|
76
86
|
end
|
77
87
|
end
|
78
88
|
end
|
@@ -3,31 +3,37 @@ module Pakyow
|
|
3
3
|
class BinderSet
|
4
4
|
attr_reader :scopes
|
5
5
|
|
6
|
-
def initialize
|
6
|
+
def initialize(&block)
|
7
7
|
@scopes = {}
|
8
8
|
@options = {}
|
9
|
+
@config = {}
|
10
|
+
|
11
|
+
instance_exec(&block)
|
9
12
|
end
|
10
13
|
|
11
14
|
def scope(name, &block)
|
12
15
|
scope_eval = ScopeEval.new
|
13
|
-
bindings, options = scope_eval.eval(&block)
|
16
|
+
bindings, options, config = scope_eval.eval(&block)
|
14
17
|
|
15
18
|
@scopes[name.to_sym] = bindings
|
16
19
|
@options[name.to_sym] = options
|
20
|
+
@config[name.to_sym] = config
|
17
21
|
end
|
18
22
|
|
19
23
|
def match_for_prop(prop, scope, bindable, bindings = {})
|
20
24
|
return bindings_for_scope(scope, bindings)[prop]
|
21
25
|
end
|
22
26
|
|
23
|
-
def options_for_prop(
|
27
|
+
def options_for_prop(scope, prop, bindable, context)
|
24
28
|
if block = (@options[scope] || {})[prop]
|
25
|
-
binding_eval = BindingEval.new(
|
26
|
-
binding_eval.instance_exec(&block)
|
29
|
+
binding_eval = BindingEval.new(prop, bindable, context)
|
30
|
+
values = binding_eval.instance_exec(binding_eval.value, bindable, context, &block)
|
31
|
+
values.unshift(['', '']) if @config[scope][prop][:empty]
|
32
|
+
values
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
30
|
-
def has_prop?(
|
36
|
+
def has_prop?(scope, prop, bindings)
|
31
37
|
bindings_for_scope(scope, bindings).key? prop
|
32
38
|
end
|
33
39
|
|
@@ -43,29 +49,31 @@ module Pakyow
|
|
43
49
|
def initialize
|
44
50
|
@bindings = {}
|
45
51
|
@options = {}
|
52
|
+
@config = {}
|
46
53
|
end
|
47
54
|
|
48
55
|
def eval(&block)
|
49
56
|
self.instance_eval(&block)
|
50
|
-
return @bindings, @options
|
57
|
+
return @bindings, @options, @config
|
51
58
|
end
|
52
59
|
|
53
60
|
def binding(name, &block)
|
54
61
|
@bindings[name.to_sym] = block
|
55
62
|
end
|
56
63
|
|
57
|
-
def options(name, &block)
|
64
|
+
def options(name, empty: false, &block)
|
58
65
|
@options[name] = block
|
66
|
+
@config[name] = { empty: empty }
|
59
67
|
end
|
60
68
|
|
61
69
|
def restful(route_group)
|
62
70
|
binding(:action) {
|
63
|
-
routes =
|
71
|
+
routes = Router.instance.group(route_group)
|
64
72
|
return_data = {}
|
65
73
|
|
66
74
|
if id = bindable[:id]
|
67
75
|
return_data[:view] = lambda { |view|
|
68
|
-
view.prepend(View.from_doc(Nokogiri::HTML.fragment('<input type="hidden" name="_method" value="patch">')))
|
76
|
+
view.prepend(View.from_doc(NokogiriDoc.from_doc(Nokogiri::HTML.fragment('<input type="hidden" name="_method" value="patch">'))))
|
69
77
|
}
|
70
78
|
|
71
79
|
action = routes.path(:update, :"#{route_group}_id" => id)
|
@@ -81,22 +89,5 @@ module Pakyow
|
|
81
89
|
|
82
90
|
#TODO options
|
83
91
|
end
|
84
|
-
|
85
|
-
class BindingEval
|
86
|
-
include Helpers
|
87
|
-
|
88
|
-
attr_accessor :context
|
89
|
-
attr_reader :bindable
|
90
|
-
|
91
|
-
def initialize(prop, bindable, context)
|
92
|
-
@prop = prop
|
93
|
-
@bindable = bindable
|
94
|
-
@context = context
|
95
|
-
end
|
96
|
-
|
97
|
-
def value
|
98
|
-
bindable[@prop]
|
99
|
-
end
|
100
|
-
end
|
101
92
|
end
|
102
93
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Pakyow
|
2
|
+
module Presenter
|
3
|
+
class BindingEval
|
4
|
+
include Pakyow::Helpers
|
5
|
+
|
6
|
+
attr_reader :context, :bindable
|
7
|
+
|
8
|
+
def initialize(prop, bindable, context)
|
9
|
+
@prop = prop
|
10
|
+
@bindable = bindable
|
11
|
+
@context = context
|
12
|
+
end
|
13
|
+
|
14
|
+
def value
|
15
|
+
if bindable.is_a?(Hash)
|
16
|
+
bindable[@prop]
|
17
|
+
elsif bindable.respond_to?(@prop)
|
18
|
+
bindable.send(@prop)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,61 +1,36 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
# Returns the default template dir for store, or default.
|
40
|
-
#
|
41
|
-
def template_dir(store_name)
|
42
|
-
dirs = template_dirs
|
43
|
-
dirs.key?(store_name) ? dirs[store_name] : dirs[:default]
|
44
|
-
end
|
45
|
-
|
46
|
-
def scope_attribute
|
47
|
-
@scope_attribute || "data-scope"
|
48
|
-
end
|
49
|
-
|
50
|
-
def prop_attribute
|
51
|
-
@prop_attribute || "data-prop"
|
52
|
-
end
|
53
|
-
|
54
|
-
def container_attribute
|
55
|
-
@container_attribute || "data-container"
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
1
|
+
Pakyow::Config.register(:presenter) { |config|
|
2
|
+
|
3
|
+
# registered view stores
|
4
|
+
config.opt :view_stores, lambda {
|
5
|
+
@stores ||= {
|
6
|
+
default: File.join(Pakyow::Config.app.root, 'app', 'views')
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
# the default view for each view store
|
11
|
+
config.opt :default_views, { default: 'pakyow.html' }
|
12
|
+
|
13
|
+
# a convenience option to lookup the default_view for a view store by name
|
14
|
+
config.opt :default_view, lambda { |store_name|
|
15
|
+
views = Pakyow::Config.presenter.default_views
|
16
|
+
views.fetch(store_name) { views[:default] }
|
17
|
+
}
|
18
|
+
|
19
|
+
# the default template dir for each view store
|
20
|
+
config.opt :template_dirs, { default: '_templates' }
|
21
|
+
|
22
|
+
# a convenience option to lookup the template_dir for a view store by name
|
23
|
+
config.opt :template_dir, lambda { |store_name|
|
24
|
+
dirs = Pakyow::Config.presenter.template_dirs
|
25
|
+
dirs.fetch(store_name) { dirs[:default] }
|
26
|
+
}
|
27
|
+
|
28
|
+
# the attribute expected for scope definitions
|
29
|
+
config.opt :scope_attribute, 'data-scope'
|
30
|
+
|
31
|
+
# the attribute expected for prop definitions
|
32
|
+
config.opt :prop_attribute, 'data-prop'
|
33
|
+
|
34
|
+
# the document class used to parse and render views
|
35
|
+
config.opt :view_doc_class, StringDoc
|
36
|
+
}
|