glimmer 0.9.2 → 0.10.1
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/README.md +986 -209
- data/VERSION +1 -1
- data/lib/glimmer.rb +39 -12
- data/lib/glimmer/config.rb +33 -7
- data/lib/glimmer/data_binding/observable_array.rb +1 -1
- data/lib/glimmer/data_binding/observable_model.rb +7 -5
- data/lib/glimmer/data_binding/observer.rb +3 -6
- data/lib/glimmer/dsl/engine.rb +27 -19
- data/lib/glimmer/dsl/expression_handler.rb +2 -3
- data/lib/glimmer/excluded_keyword_error.rb +5 -0
- metadata +45 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.10.1
|
data/lib/glimmer.rb
CHANGED
@@ -5,6 +5,10 @@
|
|
5
5
|
require 'logger'
|
6
6
|
require 'set'
|
7
7
|
|
8
|
+
$LOAD_PATH.unshift(File.expand_path('..', __FILE__))
|
9
|
+
|
10
|
+
require 'glimmer/config'
|
11
|
+
|
8
12
|
# Glimmer provides a JRuby Desktop UI DSL + Data-Binding functionality
|
9
13
|
#
|
10
14
|
# A desktop UI application class must include Glimmer to gain access to Glimmer DSL
|
@@ -13,27 +17,50 @@ require 'set'
|
|
13
17
|
# Glimmer DSL dynamic keywords (e.g. label, combo, etc...) are available via method_missing
|
14
18
|
module Glimmer
|
15
19
|
#TODO make it configurable to include or not include perhaps reverting to using included
|
16
|
-
|
20
|
+
|
21
|
+
# TODO add loop detection support to avoid infinite loops (perhaps breaks after 3 repetitions and provides an option to allow it if intentional)
|
22
|
+
class << self
|
23
|
+
attr_accessor :loop_last_data
|
24
|
+
|
25
|
+
def loop_reset!(including_loop_last_data = false)
|
26
|
+
@loop_last_data = nil if including_loop_last_data
|
27
|
+
@loop = 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def loop
|
31
|
+
@loop ||= loop_reset!
|
32
|
+
end
|
33
|
+
|
34
|
+
def loop_increment!
|
35
|
+
@loop = loop + 1
|
36
|
+
end
|
37
|
+
end
|
17
38
|
|
18
39
|
def method_missing(method_symbol, *args, &block)
|
19
|
-
|
20
|
-
if
|
21
|
-
|
40
|
+
new_loop_data = [method_symbol, args, block]
|
41
|
+
if new_loop_data == Glimmer.loop_last_data
|
42
|
+
Glimmer.loop_increment!
|
43
|
+
raise "Glimmer looped #{Config.loop_max_count} times with keyword '#{new_loop_data[0]}'! Check code for errors." if Glimmer.loop == Config.loop_max_count
|
44
|
+
else
|
45
|
+
Glimmer.loop_reset!
|
22
46
|
end
|
23
|
-
Glimmer
|
47
|
+
Glimmer.loop_last_data = new_loop_data
|
48
|
+
# This if statement speeds up Glimmer in girb or whenever directly including on main object
|
49
|
+
is_excluded = Config.excluded_keyword_checkers.reduce(false) {|result, checker| result || instance_exec(method_symbol, *args, &checker) }
|
50
|
+
raise ExcludedKeywordError, "Glimmer excluded keyword: #{method_symbol}" if is_excluded
|
51
|
+
Glimmer::Config.logger.info {"Interpreting keyword: #{method_symbol}"}
|
24
52
|
Glimmer::DSL::Engine.interpret(method_symbol, *args, &block)
|
53
|
+
rescue ExcludedKeywordError => e
|
54
|
+
# TODO add a feature to show excluded keywords optionally for debugging purposes
|
55
|
+
super(method_symbol, *args, &block)
|
25
56
|
rescue InvalidKeywordError => e
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
Glimmer::Config.logger&.debug "#{e.message}\n#{e.backtrace.join("\n")}"
|
57
|
+
Glimmer::Config.logger.error {"Encountered an invalid keyword at this object: #{self}"}
|
58
|
+
Glimmer::Config.logger.error {e.full_message}
|
30
59
|
super(method_symbol, *args, &block)
|
31
60
|
end
|
32
61
|
end
|
33
62
|
|
34
|
-
$LOAD_PATH.unshift(File.expand_path('..', __FILE__))
|
35
|
-
|
36
|
-
require 'glimmer/config'
|
37
63
|
require 'glimmer/error'
|
64
|
+
require 'glimmer/excluded_keyword_error'
|
38
65
|
require 'glimmer/invalid_keyword_error'
|
39
66
|
require 'glimmer/dsl/engine'
|
data/lib/glimmer/config.rb
CHANGED
@@ -1,22 +1,48 @@
|
|
1
1
|
module Glimmer
|
2
2
|
module Config
|
3
3
|
class << self
|
4
|
+
LOOP_MAX_COUNT_DEFAULT = 100
|
5
|
+
REGEX_METHODS_EXCLUDED = /^(to_|\[)/
|
6
|
+
|
7
|
+
attr_writer :loop_max_count
|
8
|
+
|
9
|
+
def excluded_keyword_checkers
|
10
|
+
@excluded_keyword_checkers ||= reset_excluded_keyword_checkers!
|
11
|
+
end
|
12
|
+
|
13
|
+
def excluded_keyword_checkers=(checkers)
|
14
|
+
@excluded_keyword_checkers = checkers
|
15
|
+
end
|
16
|
+
|
17
|
+
def reset_excluded_keyword_checkers!
|
18
|
+
@excluded_keyword_checkers = [
|
19
|
+
lambda { |method_symbol, *args| method_symbol.to_s.match(REGEX_METHODS_EXCLUDED) }
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
def loop_max_count
|
24
|
+
@loop_max_count ||= LOOP_MAX_COUNT_DEFAULT
|
25
|
+
end
|
26
|
+
|
4
27
|
# Returns Glimmer logger (standard Ruby logger)
|
5
28
|
def logger
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
29
|
+
reset_logger! unless defined? @@logger
|
30
|
+
@@logger
|
31
|
+
end
|
32
|
+
|
33
|
+
def logger=(custom_logger)
|
34
|
+
@@logger = custom_logger
|
10
35
|
end
|
11
36
|
|
12
|
-
def
|
13
|
-
|
37
|
+
def reset_logger!
|
38
|
+
self.logger = Logger.new(STDOUT).tap do |logger|
|
39
|
+
logger.level = Logger::ERROR
|
40
|
+
end
|
14
41
|
end
|
15
42
|
end
|
16
43
|
end
|
17
44
|
end
|
18
45
|
|
19
46
|
if ENV['GLIMMER_LOGGER_LEVEL']
|
20
|
-
Glimmer::Config.enable_logging
|
21
47
|
Glimmer::Config.logger.level = ENV['GLIMMER_LOGGER_LEVEL'].downcase
|
22
48
|
end
|
@@ -47,7 +47,9 @@ module Glimmer
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def notify_observers(property_name)
|
50
|
-
property_observer_list(property_name).each
|
50
|
+
property_observer_list(property_name).to_a.each do |observer|
|
51
|
+
observer.call(send(property_name))
|
52
|
+
end
|
51
53
|
end
|
52
54
|
#TODO upon updating values, make sure dependent observers are cleared (not added as dependents here)
|
53
55
|
|
@@ -56,9 +58,9 @@ module Glimmer
|
|
56
58
|
method(property_writer_name)
|
57
59
|
ensure_array_object_observer(property_name, send(property_name))
|
58
60
|
begin
|
59
|
-
|
61
|
+
singleton_method("__original_#{property_writer_name}")
|
60
62
|
rescue
|
61
|
-
old_method = self.class.instance_method(property_writer_name)
|
63
|
+
old_method = self.class.instance_method(property_writer_name) rescue self.method(property_writer_name)
|
62
64
|
define_singleton_method("__original_#{property_writer_name}", old_method)
|
63
65
|
define_singleton_method(property_writer_name) do |value|
|
64
66
|
old_value = self.send(property_name)
|
@@ -69,8 +71,8 @@ module Glimmer
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
rescue => e
|
72
|
-
#
|
73
|
-
Glimmer::Config.logger
|
74
|
+
#ignore writing if no property writer exists
|
75
|
+
Glimmer::Config.logger.debug {"No need to observe property writer: #{property_writer_name}\n#{e.message}\n#{e.backtrace.join("\n")}"}
|
74
76
|
end
|
75
77
|
|
76
78
|
def unregister_dependent_observers(property_name, old_value)
|
@@ -75,6 +75,7 @@ module Glimmer
|
|
75
75
|
alias observe register
|
76
76
|
|
77
77
|
def unregister(observable, property = nil)
|
78
|
+
return unless observable.is_a?(Observable)
|
78
79
|
# TODO optimize performance in the future via indexing and/or making a registration official object/class
|
79
80
|
observable.remove_observer(*[self, property].compact)
|
80
81
|
registration = registration_for(observable, property)
|
@@ -90,16 +91,12 @@ module Glimmer
|
|
90
91
|
thedependents = dependents_for(registration).select do |thedependent|
|
91
92
|
thedependent.observable == dependent_observable
|
92
93
|
end
|
93
|
-
thedependents.each
|
94
|
-
thedependent.unregister
|
95
|
-
end
|
94
|
+
thedependents.each(&:unregister)
|
96
95
|
end
|
97
96
|
|
98
97
|
# cleans up all registrations in observables
|
99
98
|
def unregister_all_observables
|
100
|
-
registrations.each
|
101
|
-
registration.unregister
|
102
|
-
end
|
99
|
+
registrations.each(&:unregister)
|
103
100
|
end
|
104
101
|
alias unobserve_all_observables unregister_all_observables
|
105
102
|
|
data/lib/glimmer/dsl/engine.rb
CHANGED
@@ -11,6 +11,8 @@ module Glimmer
|
|
11
11
|
# When DSL engine interprets an expression, it attempts to handle
|
12
12
|
# with ordered expression array specified via `.expressions=` method.
|
13
13
|
class Engine
|
14
|
+
MESSAGE_NO_DSLS = "Glimmer has no DSLs configured. Add glimmer-dsl-swt gem or visit https://github.com/AndyObtiva/glimmer#multi-dsl-support for more details.\n"
|
15
|
+
|
14
16
|
class << self
|
15
17
|
def dsl=(dsl_name)
|
16
18
|
dsl_name = dsl_name&.to_sym
|
@@ -69,6 +71,16 @@ module Glimmer
|
|
69
71
|
# Static expressions indexed by keyword and dsl
|
70
72
|
def static_expressions
|
71
73
|
@static_expressions ||= {}
|
74
|
+
end
|
75
|
+
|
76
|
+
# Sets dynamic expression chains of responsibility. Useful for internal testing
|
77
|
+
def dynamic_expression_chains_of_responsibility=(chains)
|
78
|
+
@dynamic_expression_chains_of_responsibility = chains
|
79
|
+
end
|
80
|
+
|
81
|
+
# Sets static expressions. Useful for internal testing
|
82
|
+
def static_expressions=(expressions)
|
83
|
+
@static_expressions = expressions
|
72
84
|
end
|
73
85
|
|
74
86
|
# Sets an ordered array of DSL expressions to support
|
@@ -84,7 +96,7 @@ module Glimmer
|
|
84
96
|
dynamic_expression_chains_of_responsibility[dsl] = expression_names.reverse.map do |expression_name|
|
85
97
|
expression_class(dsl_namespace, expression_name).new
|
86
98
|
end.reduce(nil) do |last_expresion_handler, expression|
|
87
|
-
Glimmer::Config.logger
|
99
|
+
Glimmer::Config.logger.info {"Adding dynamic expression: #{expression.class.name}"}
|
88
100
|
expression_handler = ExpressionHandler.new(expression)
|
89
101
|
expression_handler.next = last_expresion_handler if last_expresion_handler
|
90
102
|
expression_handler
|
@@ -92,21 +104,22 @@ module Glimmer
|
|
92
104
|
end
|
93
105
|
|
94
106
|
def add_static_expression(static_expression)
|
95
|
-
Glimmer::Config.logger
|
107
|
+
Glimmer::Config.logger.info {"Adding static expression: #{static_expression.class.name}"}
|
96
108
|
keyword = static_expression.class.keyword
|
97
109
|
static_expression_dsl = static_expression.class.dsl
|
98
110
|
static_expressions[keyword] ||= {}
|
99
111
|
static_expressions[keyword][static_expression_dsl] = static_expression
|
100
112
|
Glimmer.send(:define_method, keyword) do |*args, &block|
|
101
|
-
|
102
|
-
|
113
|
+
if Glimmer::DSL::Engine.no_dsls?
|
114
|
+
puts Glimmer::DSL::Engine::MESSAGE_NO_DSLS
|
115
|
+
else
|
116
|
+
retrieved_static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl]
|
103
117
|
static_expression_dsl = (Glimmer::DSL::Engine.static_expressions[keyword].keys - Glimmer::DSL::Engine.disabled_dsls).first if retrieved_static_expression.nil?
|
104
118
|
interpretation = nil
|
105
119
|
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))
|
106
120
|
begin
|
107
121
|
interpretation = Glimmer::DSL::Engine.interpret(keyword, *args, &block)
|
108
122
|
rescue => e
|
109
|
-
Glimmer::DSL::Engine.reset
|
110
123
|
raise e if static_expression_dsl.nil? || !Glimmer::DSL::Engine.static_expressions[keyword][static_expression_dsl].is_a?(TopLevelExpression)
|
111
124
|
end
|
112
125
|
end
|
@@ -119,18 +132,14 @@ module Glimmer
|
|
119
132
|
if !static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block)
|
120
133
|
raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent}"
|
121
134
|
else
|
122
|
-
Glimmer::Config.logger
|
135
|
+
Glimmer::Config.logger.info {"#{static_expression.class.name} will handle expression keyword #{keyword}"}
|
123
136
|
static_expression.interpret(Glimmer::DSL::Engine.parent, keyword, *args, &block).tap do |ui_object|
|
124
137
|
Glimmer::DSL::Engine.add_content(ui_object, static_expression, &block) unless block.nil?
|
125
138
|
Glimmer::DSL::Engine.dsl_stack.pop
|
126
139
|
end
|
127
140
|
end
|
128
141
|
end
|
129
|
-
|
130
|
-
# Glimmer::DSL::Engine.dsl_stack.pop
|
131
|
-
Glimmer::DSL::Engine.reset
|
132
|
-
raise e
|
133
|
-
end
|
142
|
+
end
|
134
143
|
end
|
135
144
|
end
|
136
145
|
|
@@ -145,7 +154,7 @@ module Glimmer
|
|
145
154
|
# Interprets Glimmer dynamic DSL expression consisting of keyword, args, and block (e.g. shell(:no_resize) { ... })
|
146
155
|
def interpret(keyword, *args, &block)
|
147
156
|
if no_dsls?
|
148
|
-
puts
|
157
|
+
puts MESSAGE_NO_DSLS
|
149
158
|
return
|
150
159
|
end
|
151
160
|
keyword = keyword.to_s
|
@@ -156,10 +165,6 @@ module Glimmer
|
|
156
165
|
add_content(ui_object, expression, &block)
|
157
166
|
dsl_stack.pop
|
158
167
|
end
|
159
|
-
rescue StandardError => e
|
160
|
-
# dsl_stack.pop
|
161
|
-
reset
|
162
|
-
raise e
|
163
168
|
end
|
164
169
|
|
165
170
|
# Adds content block to parent UI object
|
@@ -171,9 +176,12 @@ module Glimmer
|
|
171
176
|
if block_given? && expression.is_a?(ParentExpression)
|
172
177
|
dsl_stack.push(expression.class.dsl)
|
173
178
|
parent_stack.push(parent)
|
174
|
-
|
175
|
-
|
176
|
-
|
179
|
+
begin
|
180
|
+
expression.add_content(parent, &block)
|
181
|
+
ensure
|
182
|
+
parent_stack.pop
|
183
|
+
dsl_stack.pop
|
184
|
+
end
|
177
185
|
end
|
178
186
|
end
|
179
187
|
|
@@ -23,9 +23,9 @@ module Glimmer
|
|
23
23
|
# Otherwise, it forwards to the next handler configured via `#next=` method
|
24
24
|
# If there is no handler next, then it raises an error
|
25
25
|
def handle(parent, keyword, *args, &block)
|
26
|
-
Glimmer::Config.logger
|
26
|
+
Glimmer::Config.logger.info {"Attempting to handle #{keyword} with #{@expression.class.name.split(":").last}"}
|
27
27
|
if @expression.can_interpret?(parent, keyword, *args, &block)
|
28
|
-
Glimmer::Config.logger
|
28
|
+
Glimmer::Config.logger.info {"#{@expression.class.name} will handle expression keyword #{keyword}"}
|
29
29
|
return @expression
|
30
30
|
elsif @next_expression_handler
|
31
31
|
return @next_expression_handler.handle(parent, keyword, *args, &block)
|
@@ -34,7 +34,6 @@ module Glimmer
|
|
34
34
|
message = "Glimmer keyword #{keyword} with args #{args} cannot be handled"
|
35
35
|
message += " inside parent #{parent}" if parent
|
36
36
|
message += "! Check the validity of the code."
|
37
|
-
# Glimmer::Config.logger&.error message
|
38
37
|
raise InvalidKeywordError, message
|
39
38
|
end
|
40
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -132,6 +132,48 @@ dependencies:
|
|
132
132
|
- - "<"
|
133
133
|
- !ruby/object:Gem::Version
|
134
134
|
version: 7.0.0
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
requirement: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - '='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: 0.8.23
|
141
|
+
name: coveralls
|
142
|
+
type: :development
|
143
|
+
prerelease: false
|
144
|
+
version_requirements: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - '='
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: 0.8.23
|
149
|
+
- !ruby/object:Gem::Dependency
|
150
|
+
requirement: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - "~>"
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: 0.16.1
|
155
|
+
name: simplecov
|
156
|
+
type: :development
|
157
|
+
prerelease: false
|
158
|
+
version_requirements: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - "~>"
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: 0.16.1
|
163
|
+
- !ruby/object:Gem::Dependency
|
164
|
+
requirement: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - "~>"
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: 0.7.0
|
169
|
+
name: simplecov-lcov
|
170
|
+
type: :development
|
171
|
+
prerelease: false
|
172
|
+
version_requirements: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - "~>"
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: 0.7.0
|
135
177
|
description: Ruby Desktop Development GUI Library (JRuby on SWT)
|
136
178
|
email: andy.am@gmail.com
|
137
179
|
executables: []
|
@@ -157,6 +199,7 @@ files:
|
|
157
199
|
- lib/glimmer/dsl/static_expression.rb
|
158
200
|
- lib/glimmer/dsl/top_level_expression.rb
|
159
201
|
- lib/glimmer/error.rb
|
202
|
+
- lib/glimmer/excluded_keyword_error.rb
|
160
203
|
- lib/glimmer/invalid_keyword_error.rb
|
161
204
|
homepage: http://github.com/AndyObtiva/glimmer
|
162
205
|
licenses:
|