glimmer-dsl-web 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.10
1
+ 0.0.11
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer-dsl-web 0.0.10 ruby lib
5
+ # stub: glimmer-dsl-web 0.0.11 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-web".freeze
9
- s.version = "0.0.10".freeze
9
+ s.version = "0.0.11".freeze
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Andy Maleh".freeze]
14
- s.date = "2024-01-05"
14
+ s.date = "2024-01-06"
15
15
  s.description = "Glimmer DSL for Web (Ruby in the Browser Web GUI Frontend Library) - Enables frontend GUI development with Ruby by adopting a DSL that follows web-like HTML syntax, enabling the transfer of HTML/CSS/JS skills to Ruby frontend development. This library relies on Opal Ruby.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.extra_rdoc_files = [
@@ -37,7 +37,9 @@ Gem::Specification.new do |s|
37
37
  "lib/glimmer-dsl-web/samples/hello/hello_form.rb",
38
38
  "lib/glimmer-dsl-web/samples/hello/hello_glimmer_component_helper/address_form.rb",
39
39
  "lib/glimmer-dsl-web/samples/hello/hello_input_date_time.rb",
40
+ "lib/glimmer-dsl-web/samples/hello/hello_observer.rb",
40
41
  "lib/glimmer-dsl-web/samples/hello/hello_world.rb",
42
+ "lib/glimmer-dsl-web/samples/regular/button_counter.rb",
41
43
  "lib/glimmer-dsl-web/vendor/jquery.js",
42
44
  "lib/glimmer/config/opal_logger.rb",
43
45
  "lib/glimmer/data_binding/element_binding.rb",
@@ -49,6 +51,7 @@ Gem::Specification.new do |s|
49
51
  "lib/glimmer/dsl/web/element_expression.rb",
50
52
  "lib/glimmer/dsl/web/general_element_expression.rb",
51
53
  "lib/glimmer/dsl/web/listener_expression.rb",
54
+ "lib/glimmer/dsl/web/observe_expression.rb",
52
55
  "lib/glimmer/dsl/web/p_expression.rb",
53
56
  "lib/glimmer/dsl/web/property_expression.rb",
54
57
  "lib/glimmer/dsl/web/select_expression.rb",
@@ -74,7 +77,7 @@ Gem::Specification.new do |s|
74
77
  s.add_runtime_dependency(%q<opal>.freeze, ["= 1.8.2".freeze])
75
78
  s.add_runtime_dependency(%q<opal-rails>.freeze, ["= 2.0.3".freeze])
76
79
  s.add_runtime_dependency(%q<opal-async>.freeze, ["~> 1.4.0".freeze])
77
- s.add_runtime_dependency(%q<opal-jquery>.freeze, ["~> 0.4.6".freeze])
80
+ s.add_runtime_dependency(%q<opal-jquery>.freeze, ["~> 0.5.0".freeze])
78
81
  s.add_runtime_dependency(%q<to_collection>.freeze, [">= 2.0.1".freeze, "< 3.0.0".freeze])
79
82
  s.add_development_dependency(%q<puts_debuggerer>.freeze, [">= 0".freeze])
80
83
  s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0".freeze, "< 14.0.0".freeze])
@@ -21,8 +21,9 @@ module Glimmer
21
21
  if block.source_location && (block.source_location == parent.content&.__getobj__&.source_location)
22
22
  parent.content.call(parent) unless parent.content.called?
23
23
  else
24
- super
24
+ super(parent, keyword, *args, &block)
25
25
  end
26
+ parent.post_add_content
26
27
  end
27
28
  end
28
29
  end
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2023-2024 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
1
22
  require 'glimmer/dsl/engine'
2
23
  require 'glimmer/dsl/web/element_expression'
3
24
  require 'glimmer/dsl/web/listener_expression'
@@ -9,6 +30,7 @@ require 'glimmer/dsl/web/data_binding_expression'
9
30
  require 'glimmer/dsl/web/content_data_binding_expression'
10
31
  require 'glimmer/dsl/web/shine_data_binding_expression'
11
32
  require 'glimmer/dsl/web/component_expression'
33
+ require 'glimmer/dsl/web/observe_expression'
12
34
 
13
35
  module Glimmer
14
36
  module DSL
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2023-2024 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/dsl/static_expression'
23
+ require 'glimmer/dsl/top_level_expression'
24
+ require 'glimmer/dsl/observe_expression'
25
+ require 'glimmer/web/component'
26
+
27
+ module Glimmer
28
+ module DSL
29
+ module SWT
30
+ class ObserveExpression < StaticExpression
31
+ include TopLevelExpression
32
+ include Glimmer::DSL::ObserveExpression
33
+
34
+ def interpret(parent, keyword, *args, &block)
35
+ observer_registration = super(parent, keyword, *args, &block)
36
+ Glimmer::Web::Component.interpretation_stack.last&.observer_registrations&.push(observer_registration)
37
+ observer_registration
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -15,13 +15,11 @@ module GlimmerHelper
15
15
  component_args_json = JSON.dump(component_args)
16
16
  opal_script = <<~Opal
17
17
  require 'glimmer-dsl-web'
18
- Document.ready? do
19
- component_args_json = '#{component_args_json}'
20
- component_args = JSON.parse(component_args_json)
21
- component_args << {} if !component_args.last.is_a?(Hash)
22
- component_args.last[:parent] = "##{component_id}"
23
- #{component_class_name}.render(*component_args)
24
- end
18
+ component_args_json = '#{component_args_json}'
19
+ component_args = JSON.parse(component_args_json)
20
+ component_args << {} if !component_args.last.is_a?(Hash)
21
+ component_args.last[:parent] = "##{component_id}"
22
+ #{component_class_name}.render(*component_args)
25
23
  Opal
26
24
  content_tag(:div, id: component_script_container_id, class: ['glimmer_component_script_container', "#{component_file}_script_container"]) do
27
25
  content_tag(:div, '', id: component_id, class: ['glimmer_component', component_file]) +
@@ -176,6 +176,10 @@ module Glimmer
176
176
  def reset_component_namespaces
177
177
  @component_namespaces = Set[Object, Glimmer::Web]
178
178
  end
179
+
180
+ def interpretation_stack
181
+ @interpretation_stack ||= []
182
+ end
179
183
  end
180
184
  # <- end of class methods
181
185
 
@@ -184,6 +188,7 @@ module Glimmer
184
188
  alias parent_proxy parent
185
189
 
186
190
  def initialize(parent, args, options, &content)
191
+ Component.interpretation_stack.push(self)
187
192
  @parent = parent
188
193
  options = args.delete_at(-1) if args.is_a?(Array) && args.last.is_a?(Hash)
189
194
  if args.is_a?(Hash)
@@ -203,6 +208,14 @@ module Glimmer
203
208
  @parent ||= @markup_root.parent
204
209
  raise Glimmer::Error, 'Invalid Glimmer web component for having an empty markup! Please fill markup block!' if @markup_root.nil?
205
210
  execute_hooks('after_render')
211
+
212
+ # TODO adapt for web
213
+ observer_registration_cleanup_listener = proc do
214
+ observer_registrations.compact.each(&:deregister)
215
+ observer_registrations.clear
216
+ end
217
+ @markup_root.handle_observation_request('on_remove', observer_registration_cleanup_listener)
218
+ post_add_content if content.nil?
206
219
  end
207
220
 
208
221
  # Subclasses may override to perform post initialization work on an added child
@@ -210,6 +223,15 @@ module Glimmer
210
223
  # No Op by default
211
224
  end
212
225
 
226
+ def post_add_content
227
+ Component.interpretation_stack.pop
228
+ end
229
+
230
+ # This stores observe keyword registrations of model/attribute observers
231
+ def observer_registrations
232
+ @observer_registrations ||= []
233
+ end
234
+
213
235
  def can_handle_observation_request?(observation_request)
214
236
  observation_request = observation_request.to_s
215
237
  result = false
@@ -139,11 +139,14 @@ module Glimmer
139
139
  @children.dup.each do |child|
140
140
  child.remove
141
141
  end
142
+ on_remove_listeners = listeners_for('on_remove').dup
142
143
  remove_all_listeners
143
144
  dom_element.remove
144
145
  parent&.post_remove_child(self)
145
146
  @removed = true
146
- # listeners_for('widget_removed').each {|listener| listener.call(Event.new(widget: self))}
147
+ on_remove_listeners.each do |listener|
148
+ listener.original_event_listener.call(EventProxy.new(listener: listener))
149
+ end
147
150
  end
148
151
 
149
152
  def remove_all_listeners
@@ -217,10 +220,12 @@ module Glimmer
217
220
  if parent_selector
218
221
  Document.find(parent_selector)
219
222
  else
220
- # TODO consider moving this to initializer
221
223
  options[:parent] ||= 'body'
222
224
  the_element = Document.find(options[:parent])
223
- the_element = Document.find('body') if the_element.length == 0
225
+ if the_element.length == 0
226
+ options[:parent] = 'body'
227
+ the_element = Document.find('body')
228
+ end
224
229
  the_element
225
230
  end
226
231
  end
@@ -433,22 +438,12 @@ module Glimmer
433
438
  end
434
439
 
435
440
  def handle_observation_request(keyword, original_event_listener)
436
- # case keyword
437
- # when 'on_widget_removed'
438
- # listeners_for(keyword.sub(/^on_/, '')) << original_event_listener.to_proc
439
- # else
440
- handle_javascript_observation_request(keyword, original_event_listener)
441
- # end
442
- end
443
-
444
- def handle_javascript_observation_request(keyword, original_event_listener)
445
441
  listener = ListenerProxy.new(
446
442
  element: self,
447
443
  selector: selector,
448
444
  dom_element: dom_element,
449
445
  event_attribute: keyword,
450
- listener: original_event_listener,
451
- original_event_listener: original_event_listener
446
+ original_event_listener: original_event_listener,
452
447
  )
453
448
  listener.register
454
449
  listeners_for(keyword) << listener
@@ -24,9 +24,11 @@ module Glimmer
24
24
  class EventProxy
25
25
  attr_reader :js_event, :listener
26
26
 
27
- def initialize(js_event:, listener:)
28
- @js_event = js_event
27
+ # Instantiates EventProxy
28
+ # When js_event is nil, it is a custom event
29
+ def initialize(listener:, js_event: nil)
29
30
  @listener = listener
31
+ @js_event = js_event
30
32
  end
31
33
 
32
34
  def element = listener.element
@@ -34,6 +36,7 @@ module Glimmer
34
36
  def event_attribute = listener.event_attribute
35
37
 
36
38
  def original_event
39
+ return if js_event.nil?
37
40
  Native(`#{js_event.to_n}.originalEvent`)
38
41
  end
39
42
 
@@ -41,14 +44,14 @@ module Glimmer
41
44
  property_name = method_name.to_s.camelcase
42
45
  super(method_name, include_private) ||
43
46
  js_event.respond_to?(method_name, include_private) ||
44
- `#{property_name} in #{original_event.to_n}`
47
+ (original_event && `#{property_name} in #{original_event.to_n}`)
45
48
  end
46
49
 
47
50
  def method_missing(method_name, *args, &block)
48
51
  property_name = method_name.to_s.camelcase
49
52
  if js_event.respond_to?(method_name, true)
50
53
  js_event.send(method_name, *args, &block)
51
- elsif `#{property_name} in #{original_event.to_n}`
54
+ elsif (original_event && `#{property_name} in #{original_event.to_n}`)
52
55
  original_event[property_name]
53
56
  else
54
57
  super(method_name, *args, &block)
@@ -24,33 +24,34 @@ require 'glimmer/web/event_proxy'
24
24
  module Glimmer
25
25
  module Web
26
26
  class ListenerProxy
27
- attr_reader :element, :event_attribute, :event_name, :dom_element, :selector, :listener, :js_listener, :original_event_listener
27
+ attr_reader :element, :event_attribute, :event_name, :dom_element, :selector, :js_listener, :original_event_listener
28
28
 
29
- def initialize(element:, event_attribute:, dom_element:, selector:, listener:)
29
+ def initialize(element:, event_attribute:, dom_element:, selector:, original_event_listener:)
30
30
  @element = element
31
31
  @event_attribute = event_attribute
32
- @event_name = event_attribute.sub(/^on/, '')
32
+ @event_name = event_attribute.sub(/^on_/, '').sub(/^on/, '')
33
33
  @dom_element = dom_element
34
34
  @selector = selector
35
- @listener = listener
36
- @js_listener = lambda do |js_event|
37
- event = EventProxy.new(js_event: js_event, listener: self)
38
- result = listener.call(event)
39
- result = true if result.nil?
40
- result
35
+ if !event_attribute.start_with?('on_') # custom event
36
+ @js_listener = lambda do |js_event|
37
+ event = EventProxy.new(js_event: js_event, listener: self)
38
+ result = original_event_listener.call(event)
39
+ result = true if result.nil?
40
+ result
41
+ end
41
42
  end
42
43
  @original_event_listener = original_event_listener
43
44
  end
44
45
 
45
46
  def register
46
- @dom_element.on(@event_name, &@js_listener)
47
+ @dom_element.on(@event_name, &@js_listener) unless @js_listener.nil?
47
48
  end
48
49
  alias observe register
49
50
  alias reregister register
50
51
 
51
52
  def unregister
52
53
  # TODO contribute fix to opal to allow passing observer with & to off with selector not specified as nil
53
- @dom_element.off(@event_name, @js_listener)
54
+ @dom_element.off(@event_name, @js_listener) unless @js_listener.nil?
54
55
  @element.listeners_for(@event_attribute).delete(self)
55
56
  end
56
57
  alias unobserve unregister
@@ -0,0 +1,88 @@
1
+ # Copyright (c) 2023-2024 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer-dsl-web'
23
+
24
+ class NumberHolder
25
+ attr_accessor :number
26
+
27
+ def initialize
28
+ self.number = 50
29
+ end
30
+ end
31
+
32
+ class HelloObserver
33
+ include Glimmer::Web::Component
34
+
35
+ before_render do
36
+ @number_holder = NumberHolder.new
37
+ end
38
+
39
+ after_render do
40
+ # observe Model attribute @number_holder.number for changes and update View
41
+ observe(@number_holder, :number) do
42
+ number_string = @number_holder.number.to_s
43
+ @number_input.value = number_string unless @number_input.value == number_string
44
+ @range_input.value = number_string unless @range_input.value == number_string
45
+ end
46
+ # Bidirectional Data-Binding does the same thing automatically
47
+ # Just disable the observe block above as well as the oninput listeners below
48
+ # and enable the `value <=> [@number_holder, :number]` lines to try the data-binding version
49
+ # Learn more about Bidirectional and Unidirectional Data-Binding in hello_data_binding.rb
50
+ end
51
+
52
+ markup {
53
+ div {
54
+ div {
55
+ @number_input = input(type: 'number', value: @number_holder.number, min: 0, max: 100) {
56
+ # oninput listener updates Model attribute @number_holder.number
57
+ oninput do
58
+ @number_holder.number = @number_input.value.to_i
59
+ end
60
+
61
+ # Bidirectional Data-Binding simplifies the implementation significantly
62
+ # by enabling the following line and disabling oninput listeners as well
63
+ # as the after_body observe block observer
64
+ # Learn more about Bidirectional and Unidirectional Data-Binding in hello_data_binding.rb
65
+ # value <=> [@number_holder, :number]
66
+ }
67
+ }
68
+ div {
69
+ @range_input = input(type: 'range', value: @number_holder.number, min: 0, max: 100) {
70
+ # oninput listener updates Model attribute @number_holder.number
71
+ oninput do
72
+ @number_holder.number = @range_input.value.to_i
73
+ end
74
+
75
+ # Bidirectional Data-Binding simplifies the implementation significantly
76
+ # by enabling the following line and disabling oninput listeners as well
77
+ # as the after_body observe block observer
78
+ # Learn more about Bidirectional and Unidirectional Data-Binding in hello_data_binding.rb
79
+ # value <=> [@number_holder, :number]
80
+ }
81
+ }
82
+ }
83
+ }
84
+ end
85
+
86
+ Document.ready? do
87
+ HelloObserver.render
88
+ end
@@ -0,0 +1,36 @@
1
+ require 'glimmer-dsl-web'
2
+
3
+ class Counter
4
+ attr_accessor :count
5
+
6
+ def initialize
7
+ self.count = 0
8
+ end
9
+ end
10
+
11
+ class ButtonCounter
12
+ include Glimmer::Web::Component
13
+
14
+ before_render do
15
+ @counter = Counter.new
16
+ end
17
+
18
+ markup {
19
+ div {
20
+ button {
21
+ # Unidirectional Data-Binding indicating that on every change to @counter.count, the value
22
+ # is read and converted to "Click To Increment: #{value} ", and then automatically
23
+ # copied to button innerText (content) to display to the user
24
+ inner_text <= [@counter, :count,
25
+ on_read: ->(value) { "Click To Increment: #{value} " }
26
+ ]
27
+
28
+ onclick {
29
+ @counter.count += 1
30
+ }
31
+ }
32
+ }
33
+ }
34
+ end
35
+
36
+ ButtonCounter.render
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-05 00:00:00.000000000 Z
11
+ date: 2024-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 0.4.6
103
+ version: 0.5.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 0.4.6
110
+ version: 0.5.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: to_collection
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -259,7 +259,9 @@ files:
259
259
  - lib/glimmer-dsl-web/samples/hello/hello_form.rb
260
260
  - lib/glimmer-dsl-web/samples/hello/hello_glimmer_component_helper/address_form.rb
261
261
  - lib/glimmer-dsl-web/samples/hello/hello_input_date_time.rb
262
+ - lib/glimmer-dsl-web/samples/hello/hello_observer.rb
262
263
  - lib/glimmer-dsl-web/samples/hello/hello_world.rb
264
+ - lib/glimmer-dsl-web/samples/regular/button_counter.rb
263
265
  - lib/glimmer-dsl-web/vendor/jquery.js
264
266
  - lib/glimmer/config/opal_logger.rb
265
267
  - lib/glimmer/data_binding/element_binding.rb
@@ -271,6 +273,7 @@ files:
271
273
  - lib/glimmer/dsl/web/element_expression.rb
272
274
  - lib/glimmer/dsl/web/general_element_expression.rb
273
275
  - lib/glimmer/dsl/web/listener_expression.rb
276
+ - lib/glimmer/dsl/web/observe_expression.rb
274
277
  - lib/glimmer/dsl/web/p_expression.rb
275
278
  - lib/glimmer/dsl/web/property_expression.rb
276
279
  - lib/glimmer/dsl/web/select_expression.rb