glimmer-dsl-opal 0.0.3 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/README.md +1049 -35
  4. data/VERSION +1 -1
  5. data/lib/glimmer-dsl-opal.rb +5 -2
  6. data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
  7. data/lib/glimmer/data_binding/list_selection_binding.rb +51 -0
  8. data/lib/glimmer/data_binding/table_items_binding.rb +67 -0
  9. data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
  10. data/lib/glimmer/dsl/opal/browser_expression.rb +17 -0
  11. data/lib/glimmer/dsl/opal/column_properties_expression.rb +22 -0
  12. data/lib/glimmer/dsl/opal/dsl.rb +14 -0
  13. data/lib/glimmer/dsl/opal/list_expression.rb +17 -0
  14. data/lib/glimmer/dsl/opal/list_selection_data_binding_expression.rb +42 -0
  15. data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
  16. data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
  17. data/lib/glimmer/dsl/opal/tab_folder_expression.rb +17 -0
  18. data/lib/glimmer/dsl/opal/tab_item_expression.rb +17 -0
  19. data/lib/glimmer/dsl/opal/table_column_expression.rb +17 -0
  20. data/lib/glimmer/dsl/opal/table_expression.rb +17 -0
  21. data/lib/glimmer/dsl/opal/table_items_data_binding_expression.rb +29 -0
  22. data/lib/glimmer/opal/display_proxy.rb +23 -0
  23. data/lib/glimmer/opal/div_proxy.rb +11 -2
  24. data/lib/glimmer/opal/document_proxy.rb +141 -11
  25. data/lib/glimmer/opal/element_proxy.rb +38 -15
  26. data/lib/glimmer/opal/grid_layout_proxy.rb +3 -1
  27. data/lib/glimmer/opal/iframe_proxy.rb +23 -0
  28. data/lib/glimmer/opal/input_proxy.rb +8 -4
  29. data/lib/glimmer/opal/label_proxy.rb +1 -1
  30. data/lib/glimmer/opal/layout_data_proxy.rb +23 -2
  31. data/lib/glimmer/opal/list_proxy.rb +80 -0
  32. data/lib/glimmer/opal/modal.rb +94 -0
  33. data/lib/glimmer/opal/point.rb +5 -0
  34. data/lib/glimmer/opal/select_proxy.rb +1 -1
  35. data/lib/glimmer/opal/tab_folder.rb +53 -0
  36. data/lib/glimmer/opal/tab_item.rb +98 -0
  37. data/lib/glimmer/opal/table_column.rb +50 -0
  38. data/lib/glimmer/opal/table_item.rb +136 -0
  39. data/lib/glimmer/opal/table_proxy.rb +149 -0
  40. data/lib/samples/elaborate/contact_manager.rb +1 -2
  41. data/lib/samples/elaborate/login.rb +0 -1
  42. data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
  43. data/lib/samples/hello/hello_tab.rb +2 -2
  44. metadata +30 -14
  45. data/lib/glimmer/config.rb +0 -22
  46. data/lib/glimmer/dsl/engine.rb +0 -193
  47. data/lib/glimmer/dsl/expression.rb +0 -42
  48. data/lib/glimmer/dsl/expression_handler.rb +0 -48
  49. data/lib/glimmer/dsl/parent_expression.rb +0 -12
  50. data/lib/glimmer/dsl/static_expression.rb +0 -36
  51. data/lib/glimmer/dsl/top_level_expression.rb +0 -7
  52. data/lib/glimmer/error.rb +0 -6
  53. data/lib/glimmer/invalid_keyword_error.rb +0 -6
@@ -1,193 +0,0 @@
1
- require 'glimmer'
2
- require 'glimmer/dsl/expression_handler'
3
-
4
- module Glimmer
5
- module DSL
6
- # Glimmer DSL Engine
7
- #
8
- # Follows Interpreter and Chain of Responsibility Design Patterns
9
- #
10
- # When DSL engine interprets an expression, it attempts to handle
11
- # with ordered expression array specified via `.expressions=` method.
12
- class Engine
13
- class << self
14
- def dsl=(dsl_name)
15
- dsl_name = dsl_name&.to_sym
16
- if dsl_name
17
- dsl_stack.push(dsl_name)
18
- else
19
- dsl_stack.clear
20
- end
21
- end
22
-
23
- def dsl
24
- dsl_stack.last
25
- end
26
-
27
- def dsls
28
- static_expressions.values.map(&:keys).flatten.uniq
29
- end
30
-
31
- def disable_dsl(dsl_name)
32
- dsl_name = dsl_name.to_sym
33
- disabled_dsls << dsl_name
34
- end
35
-
36
- def enable_dsl(dsl_name)
37
- dsl_name = dsl_name.to_sym
38
- disabled_dsls.delete(dsl_name)
39
- end
40
-
41
- def disabled_dsls
42
- @disabled_dsls ||= []
43
- end
44
-
45
- def enabled_dsls=(dsl_names)
46
- dsls.each {|dsl_name| disable_dsl(dsl_name)}
47
- dsl_names.each {|dsl_name| enable_dsl(dsl_name)}
48
- end
49
-
50
- # Resets Glimmer's engine activity and configuration. Useful in rspec before or after blocks in tests.
51
- def reset
52
- parent_stacks.values.each do |a_parent_stack|
53
- a_parent_stack.clear
54
- end
55
- dsl_stack.clear
56
- disabled_dsls.clear
57
- end
58
-
59
- # Dynamic expression chains of responsibility indexed by dsl
60
- def dynamic_expression_chains_of_responsibility
61
- @dynamic_expression_chains_of_responsibility ||= {}
62
- end
63
-
64
- # Static expressions indexed by keyword and dsl
65
- def static_expressions
66
- @static_expressions ||= {}
67
- end
68
-
69
- # Sets an ordered array of DSL expressions to support
70
- #
71
- # Every expression has an underscored name corresponding to an upper
72
- # camelcase AbstractExpression subclass name in glimmer/dsl
73
- #
74
- # They are used in order following the Chain of Responsibility Design
75
- # Pattern when interpretting a DSL expression
76
- def add_dynamic_expressions(dsl_namespace, expression_names)
77
- dsl = dsl_namespace.name.split("::").last.downcase.to_sym
78
- dynamic_expression_chains_of_responsibility[dsl] = expression_names.reverse.map do |expression_name|
79
- expression_class(dsl_namespace, expression_name).new
80
- end.reduce(nil) do |last_expresion_handler, expression|
81
- Glimmer::Config.logger&.debug "Adding dynamic expression: #{expression.class.name}"
82
- expression_handler = ExpressionHandler.new(expression)
83
- expression_handler.next = last_expresion_handler if last_expresion_handler
84
- expression_handler
85
- end
86
- end
87
-
88
- def add_static_expression(static_expression)
89
- Glimmer::Config.logger&.debug "Adding static expression: #{static_expression.class.name}"
90
- keyword = static_expression.class.keyword
91
- static_expression_dsl = static_expression.class.dsl
92
- static_expressions[keyword] ||= {}
93
- static_expressions[keyword][static_expression_dsl] = static_expression
94
- Glimmer.send(:define_method, keyword) do |*args, &block|
95
- begin
96
- retrieved_static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl]
97
- static_expression_dsl = (Glimmer::DSL::Engine.static_expressions[keyword].keys - Glimmer::DSL::Engine.disabled_dsls).last if retrieved_static_expression.nil?
98
- interpretation = nil
99
- if retrieved_static_expression.nil? && Glimmer::DSL::Engine.dsl && (static_expression_dsl.nil? || !Glimmer::DSL::Engine.static_expressions[keyword][static_expression_dsl].is_a?(TopLevelExpression))
100
- begin
101
- interpretation = Glimmer::DSL::Engine.interpret(keyword, *args, &block)
102
- rescue => e
103
- Glimmer::DSL::Engine.reset
104
- raise e if static_expression_dsl.nil? || !Glimmer::DSL::Engine.static_expressions[keyword][static_expression_dsl].is_a?(TopLevelExpression)
105
- end
106
- end
107
- if interpretation
108
- interpretation
109
- else
110
- raise Glimmer::Error, "Unsupported keyword: #{keyword}" unless static_expression_dsl || retrieved_static_expression
111
- Glimmer::DSL::Engine.dsl_stack.push(static_expression_dsl || Glimmer::DSL::Engine.dsl)
112
- static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl]
113
- if !static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block)
114
- raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent}"
115
- else
116
- Glimmer::Config.logger&.debug "#{static_expression.class.name} will handle expression keyword #{keyword}"
117
- static_expression.interpret(Glimmer::DSL::Engine.parent, keyword, *args, &block).tap do |ui_object|
118
- Glimmer::DSL::Engine.add_content(ui_object, static_expression, &block) unless block.nil?
119
- Glimmer::DSL::Engine.dsl_stack.pop
120
- end
121
- end
122
- end
123
- rescue StandardError => e
124
- # Glimmer::DSL::Engine.dsl_stack.pop
125
- Glimmer::DSL::Engine.reset
126
- raise e
127
- end
128
- end
129
- end
130
-
131
- def expression_class(dsl_namespace, expression_name)
132
- dsl_namespace.const_get(expression_class_name(expression_name).to_sym)
133
- end
134
-
135
- def expression_class_name(expression_name)
136
- "#{expression_name}_expression".camelcase(:upper)
137
- end
138
-
139
- # Interprets Glimmer dynamic DSL expression consisting of keyword, args, and block (e.g. shell(:no_resize) { ... })
140
- def interpret(keyword, *args, &block)
141
- keyword = keyword.to_s
142
- dynamic_expression_dsl = (dynamic_expression_chains_of_responsibility.keys - disabled_dsls).last if dsl.nil?
143
- dsl_stack.push(dynamic_expression_dsl || dsl)
144
- expression = dynamic_expression_chains_of_responsibility[dsl].handle(parent, keyword, *args, &block)
145
- expression.interpret(parent, keyword, *args, &block).tap do |ui_object|
146
- add_content(ui_object, expression, &block)
147
- dsl_stack.pop
148
- end
149
- rescue StandardError => e
150
- # dsl_stack.pop
151
- reset
152
- raise e
153
- end
154
-
155
- # Adds content block to parent UI object
156
- #
157
- # This allows evaluating parent UI object properties and children
158
- #
159
- # For example, a shell widget would get properties set and children added
160
- def add_content(parent, expression, &block)
161
- if block_given? && expression.is_a?(ParentExpression)
162
- dsl_stack.push(expression.class.dsl)
163
- parent_stack.push(parent)
164
- expression.add_content(parent, &block)
165
- parent_stack.pop
166
- dsl_stack.pop
167
- end
168
- end
169
-
170
- # Current parent while evaluating Glimmer DSL (nil if just started or done evaluatiing)
171
- #
172
- # Parents are maintained in a stack while evaluating Glimmer DSL
173
- # to ensure properly ordered interpretation of DSL syntax
174
- def parent
175
- parent_stack.last
176
- end
177
-
178
- def parent_stack
179
- parent_stacks[dsl] ||= []
180
- end
181
-
182
- def parent_stacks
183
- @parent_stacks ||= {}
184
- end
185
-
186
- # Enables multiple DSLs to play well with each other when mixing together
187
- def dsl_stack
188
- @dsl_stack ||= []
189
- end
190
- end
191
- end
192
- end
193
- end
@@ -1,42 +0,0 @@
1
- require 'glimmer/error'
2
-
3
- module Glimmer
4
- module DSL
5
- # Represents a Glimmer DSL expression (e.g. label(:center) { ... })
6
- #
7
- # An expression object can interpret a keyword, args, and a block into a UI object
8
- #
9
- # Expressions subclasses follow the convention of using `and` and `or`
10
- # english versino of Ruby's boolean operations. This allows easy DSL-like
11
- # readability of the rules, and easy tagging with pd when troubleshooting.
12
- class Expression
13
- class << self
14
- def dsl
15
- @dsl ||= name.split(/::/)[-2].downcase.to_sym
16
- end
17
- end
18
-
19
- # Checks if it can interpret parameters (subclass must override)
20
- def can_interpret?(parent, keyword, *args, &block)
21
- raise Error, "#can_interpret? must be implemented by an Expression subclass"
22
- end
23
-
24
- # Interprets parameters (subclass must override)
25
- def interpret(parent, keyword, *args, &block)
26
- raise Error, "#interpret must be implemented by an Expression subclass"
27
- end
28
-
29
- # Adds block content to specified parent UI object (Optional)
30
- #
31
- # Only expressions that receive a content block should implement
32
- def add_content(parent, &block)
33
- # No Op by default
34
- end
35
-
36
- # Checks if object is a Symbol or a String
37
- def textual?(object)
38
- object.is_a?(Symbol) or object.is_a?(String)
39
- end
40
- end
41
- end
42
- end
@@ -1,48 +0,0 @@
1
- require 'glimmer/invalid_keyword_error'
2
-
3
- module Glimmer
4
- module DSL
5
- # Expression handler for a Glimmer DSL specific expression
6
- #
7
- # Follows the Chain of Responsibility Design Pattern
8
- #
9
- # Handlers are configured in Glimmer::DSL in the right order
10
- # to attempt handling Glimmer DSL interpretation calls
11
- #
12
- # Each handler knows the next handler in the chain of responsibility.
13
- #
14
- # If it handles successfully, it returns. Otherwise, it forwards to the next
15
- # handler in the chain of responsibility
16
- class ExpressionHandler
17
- def initialize(expression)
18
- @expression = expression
19
- end
20
-
21
- # Handles interpretation of Glimmer DSL expression if expression supports it
22
- # If it succeeds, it returns the correct Glimmer DSL expression object
23
- # Otherwise, it forwards to the next handler configured via `#next=` method
24
- # If there is no handler next, then it raises an error
25
- def handle(parent, keyword, *args, &block)
26
- Glimmer::Config.logger&.debug "Attempting to handle #{keyword} with #{@expression.class.name.split(":").last}"
27
- if @expression.can_interpret?(parent, keyword, *args, &block)
28
- Glimmer::Config.logger&.debug "#{@expression.class.name} will handle expression keyword #{keyword}"
29
- return @expression
30
- elsif @next_expression_handler
31
- return @next_expression_handler.handle(parent, keyword, *args, &block)
32
- else
33
- # TODO see if we need a better response here (e.g. dev mode error raising vs production mode silent failure)
34
- message = "Glimmer keyword #{keyword} with args #{args} cannot be handled"
35
- message += " inside parent #{parent}" if parent
36
- message += "! Check the validity of the code."
37
- # Glimmer::Config.logger&.error message
38
- raise InvalidKeywordError, message
39
- end
40
- end
41
-
42
- # Sets the next handler in the expression handler chain of responsibility
43
- def next=(next_expression_handler)
44
- @next_expression_handler = next_expression_handler
45
- end
46
- end
47
- end
48
- end
@@ -1,12 +0,0 @@
1
- require 'glimmer/error'
2
-
3
- module Glimmer
4
- module DSL
5
- # Mixin that represents expressions that always have a content block
6
- module ParentExpression
7
- def add_content(parent, &block)
8
- block.call(parent)
9
- end
10
- end
11
- end
12
- end
@@ -1,36 +0,0 @@
1
- require 'glimmer/error'
2
- require 'glimmer/dsl/engine'
3
- require 'glimmer/dsl/expression'
4
-
5
- module Glimmer
6
- module DSL
7
- # Represents a StaticExpression for expressions where
8
- # the keyword does not vary dynamically. These static keywords are then
9
- # predefined as methods in Glimmer instead of needing method_missing
10
- #
11
- # StaticExpression subclasses may optionally implement `#can_interpret?`
12
- # (not needed if it only checks for keyword)
13
- #
14
- # StaticExpression subclasses must define `#interpret`.
15
- #
16
- # The direct parent namespace of a StaticExpression subclass must match the DSL name (case-insensitive)
17
- # (e.g. Glimmer::DSL::SWT::WidgetExpression has a DSL of :swt)
18
- class StaticExpression < Expression
19
- class << self
20
- def inherited(base)
21
- Glimmer::DSL::Engine.add_static_expression(base.new)
22
- super
23
- end
24
-
25
- def keyword
26
- @keyword ||= name.split(/::/).last.sub(/Expression$/, '').underscore
27
- end
28
- end
29
-
30
- # Subclasses may optionally implement
31
- def can_interpret?(parent, keyword, *args, &block)
32
- true
33
- end
34
- end
35
- end
36
- end
@@ -1,7 +0,0 @@
1
- module Glimmer
2
- module DSL
3
- # Mixin that represents expressions that are always at the top with parent nil
4
- module TopLevelExpression
5
- end
6
- end
7
- end
@@ -1,6 +0,0 @@
1
- module Glimmer
2
- # Represents Glimmer errors that occur due to invalid use of Glimmer
3
- # without handing control flow back to original method_missing
4
- class Error < RuntimeError
5
- end
6
- end
@@ -1,6 +0,0 @@
1
- module Glimmer
2
- # Represents Glimmer errors that occur due to invalid use of Glimmer
3
- # without handing control flow back to original method_missing
4
- class InvalidKeywordError < RuntimeError
5
- end
6
- end