glimmer-dsl-opal 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +6 -0
- data/LICENSE.txt +20 -0
- data/README.md +133 -0
- data/VERSION +1 -0
- data/lib/glimmer-dsl-opal.rb +8 -0
- data/lib/glimmer/config.rb +22 -0
- data/lib/glimmer/dsl/engine.rb +193 -0
- data/lib/glimmer/dsl/expression.rb +42 -0
- data/lib/glimmer/dsl/expression_handler.rb +48 -0
- data/lib/glimmer/dsl/opal/dsl.rb +21 -0
- data/lib/glimmer/dsl/opal/label_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/property_expression.rb +19 -0
- data/lib/glimmer/dsl/opal/shell_expression.rb +19 -0
- data/lib/glimmer/dsl/parent_expression.rb +12 -0
- data/lib/glimmer/dsl/static_expression.rb +36 -0
- data/lib/glimmer/dsl/top_level_expression.rb +7 -0
- data/lib/glimmer/error.rb +6 -0
- data/lib/glimmer/invalid_keyword_error.rb +6 -0
- data/lib/glimmer/opal/label.rb +31 -0
- data/lib/glimmer/opal/shell.rb +38 -0
- metadata +209 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 67893f26592de179a00e15688b7814762edd60ff1c036b1389d177437ffaae5d
|
4
|
+
data.tar.gz: 2a6362729a7ecbe86231f2bcab62e25a46caadee1dc82c7f8abd84180d437ea2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f8ac369bb79fcd6b8b5c46ba357f807d393e99e49303f4d983efb9a1b54551a51a2b80536b2da1111097ce9ed912ae7f7ae6d7968778ade6cd0ec13f1b45e3f3
|
7
|
+
data.tar.gz: 517dbe5aa02c3c6027e9aca9be18c88a60c99c19c362dab098aa0ddb18c42faed884d0e6815a5cb7889fbec1f55c0e19543c843773f1e8720489baad07a7af73
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2020 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.
|
data/README.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
# Glimmer DSL for Opal 0.0.1 Beta (Web GUI for Desktop Apps)
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/glimmer-dsl-opal.svg)](http://badge.fury.io/rb/glimmer-dsl-opal)
|
3
|
+
|
4
|
+
[Glimmer](https://github.com/AndyObtiva/glimmer) DSL for Opal is a web GUI adaptor for desktop apps built with [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt).
|
5
|
+
|
6
|
+
It enables running [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps on the web via [Rails](https://rubyonrails.org/) 5 and [Opal](https://opalrb.com/) 1.
|
7
|
+
|
8
|
+
NOTE: Version 0.0.1 only supports Hello, World! capabilities.
|
9
|
+
|
10
|
+
## Examples
|
11
|
+
|
12
|
+
### Hello, World!
|
13
|
+
|
14
|
+
Glimmer code (from `samples/hello/hello_world.rb`):
|
15
|
+
```ruby
|
16
|
+
require 'glimmer-dsl-opal'
|
17
|
+
|
18
|
+
include Glimmer
|
19
|
+
|
20
|
+
shell {
|
21
|
+
text 'Glimmer'
|
22
|
+
label {
|
23
|
+
text 'Hello, World!'
|
24
|
+
}
|
25
|
+
}.open
|
26
|
+
```
|
27
|
+
|
28
|
+
Run:
|
29
|
+
```
|
30
|
+
glimmer samples/hello/hello_world.rb
|
31
|
+
```
|
32
|
+
|
33
|
+
Glimmer app:
|
34
|
+
|
35
|
+
![Glimmer DSL for Opal Hello World](images/glimmer-dsl-opal-hello-world.png)
|
36
|
+
|
37
|
+
## Background
|
38
|
+
|
39
|
+
Ruby is a dynamically-typed object-oriented language, which provides great productivity gains due to its powerful expressive syntax and dynamic nature. While it is proven by the Ruby on Rails framework for web development, it currently lacks a robust platform-independent framework for building desktop applications. Given that Java libraries can now be utilized in Ruby code through JRuby, Eclipse technologies, such as SWT, JFace, and RCP can help fill the gap of desktop application development with Ruby.
|
40
|
+
|
41
|
+
## Pre-requisites
|
42
|
+
|
43
|
+
- Rails 5: [https://github.com/rails/rails/tree/5-2-stable](https://github.com/rails/rails/tree/5-2-stable)
|
44
|
+
- Opal 1: [https://github.com/opal/opal-rails](https://github.com/opal/opal-rails)
|
45
|
+
|
46
|
+
## Setup
|
47
|
+
|
48
|
+
Please follow these instructions to make Glimmer desktop apps work in Opal inside Rails 5
|
49
|
+
|
50
|
+
Start a new Rails 5 app:
|
51
|
+
|
52
|
+
```
|
53
|
+
rails new hello_world
|
54
|
+
```
|
55
|
+
|
56
|
+
Follow instructions to setup opal with a rails application: config/initializers/assets.rb
|
57
|
+
|
58
|
+
Add the following to `Gemfile`:
|
59
|
+
```
|
60
|
+
gem 'opal-rails'
|
61
|
+
gem 'opal-browser'
|
62
|
+
gem 'glimmer-dsl-opal', '~> 0.0.1', require: false
|
63
|
+
```
|
64
|
+
|
65
|
+
Edit `config/initializers/assets.rb` and add:
|
66
|
+
```
|
67
|
+
Opal.use_gem 'glimmer-dsl-opal'
|
68
|
+
```
|
69
|
+
|
70
|
+
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
require 'glimmer-dsl-opal' # brings opal and opal browser too
|
74
|
+
|
75
|
+
include Glimmer
|
76
|
+
|
77
|
+
shell {
|
78
|
+
text 'Glimmer'
|
79
|
+
label {
|
80
|
+
text 'Hello, World!'
|
81
|
+
}
|
82
|
+
}
|
83
|
+
```
|
84
|
+
|
85
|
+
Start the Rails server:
|
86
|
+
```
|
87
|
+
rails s
|
88
|
+
```
|
89
|
+
|
90
|
+
Visit `http://localhost:3000`
|
91
|
+
|
92
|
+
You should see "Hello, World!"
|
93
|
+
|
94
|
+
![Glimmer DSL for Opal Hello World](images/glimmer-dsl-opal-hello-world.png)
|
95
|
+
|
96
|
+
## Help
|
97
|
+
|
98
|
+
### Issues
|
99
|
+
|
100
|
+
You may submit [issues](https://github.com/AndyObtiva/glimmer/issues) on [GitHub](https://github.com/AndyObtiva/glimmer/issues).
|
101
|
+
|
102
|
+
[Click here to submit an issue.](https://github.com/AndyObtiva/glimmer/issues)
|
103
|
+
|
104
|
+
### IRC Channel
|
105
|
+
|
106
|
+
If you need live help, try the [#glimmer](http://widget.mibbit.com/?settings=7514b8a196f8f1de939a351245db7aa8&server=irc.mibbit.net&channel=%23glimmer) IRC channel on [irc.mibbit.net](http://widget.mibbit.com/?settings=7514b8a196f8f1de939a351245db7aa8&server=irc.mibbit.net&channel=%23glimmer). If no one was available, you may [leave a GitHub issue](https://github.com/AndyObtiva/glimmer/issues) to schedule a meetup on IRC.
|
107
|
+
|
108
|
+
[Click here to connect to #glimmer IRC channel immediately via a web interface.](http://widget.mibbit.com/?settings=7514b8a196f8f1de939a351245db7aa8&server=irc.mibbit.net&channel=%23glimmer)
|
109
|
+
|
110
|
+
## Feature Suggestions
|
111
|
+
|
112
|
+
These features have been suggested. You might see them in a future version of Glimmer. You are welcome to contribute more feature suggestions.
|
113
|
+
|
114
|
+
[TODO.md](TODO.md)
|
115
|
+
|
116
|
+
## Change Log
|
117
|
+
|
118
|
+
[CHANGELOG.md](CHANGELOG.md)
|
119
|
+
|
120
|
+
## Contributing
|
121
|
+
|
122
|
+
[CONTRIBUTING.md](CONTRIBUTING.md)
|
123
|
+
|
124
|
+
## Contributors
|
125
|
+
|
126
|
+
* [Andy Maleh](https://github.com/AndyObtiva) (Founder)
|
127
|
+
|
128
|
+
[Click here to view contributor commits.](https://github.com/AndyObtiva/glimmer-dsl-opal/graphs/contributors)
|
129
|
+
|
130
|
+
## License
|
131
|
+
|
132
|
+
Copyright (c) 2020 Andy Maleh.
|
133
|
+
See LICENSE.txt for further details.
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Glimmer
|
2
|
+
module Config
|
3
|
+
class << self
|
4
|
+
# Returns Glimmer logger (standard Ruby logger)
|
5
|
+
def logger
|
6
|
+
# unless defined? @@logger
|
7
|
+
# @@logger = Logger.new(STDOUT).tap {|logger| logger.level = Logger::WARN}
|
8
|
+
# end
|
9
|
+
@@logger if defined? @@logger
|
10
|
+
end
|
11
|
+
|
12
|
+
def enable_logging
|
13
|
+
@@logger = Logger.new(STDOUT).tap {|logger| logger.level = Logger::WARN}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if ENV['GLIMMER_LOGGER_LEVEL']
|
20
|
+
Glimmer::Config.enable_logging
|
21
|
+
Glimmer::Config.logger.level = ENV['GLIMMER_LOGGER_LEVEL'].downcase
|
22
|
+
end
|
@@ -0,0 +1,193 @@
|
|
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
|
@@ -0,0 +1,42 @@
|
|
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
|
@@ -0,0 +1,48 @@
|
|
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
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'opal'
|
2
|
+
require 'browser'
|
3
|
+
|
4
|
+
require 'glimmer/dsl/engine'
|
5
|
+
# Dir[File.expand_path('../*_expression.rb', __FILE__)].each {|f| require f}
|
6
|
+
require 'glimmer/dsl/opal/shell_expression'
|
7
|
+
require 'glimmer/dsl/opal/label_expression'
|
8
|
+
require 'glimmer/dsl/opal/property_expression'
|
9
|
+
|
10
|
+
module Glimmer
|
11
|
+
module DSL
|
12
|
+
module Opal
|
13
|
+
Engine.add_dynamic_expressions(
|
14
|
+
Opal,
|
15
|
+
%w[
|
16
|
+
property
|
17
|
+
]
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'glimmer/dsl/static_expression'
|
2
|
+
require 'glimmer/dsl/parent_expression'
|
3
|
+
require 'glimmer/opal/label'
|
4
|
+
|
5
|
+
module Glimmer
|
6
|
+
module DSL
|
7
|
+
module Opal
|
8
|
+
class LabelExpression < StaticExpression
|
9
|
+
include ParentExpression
|
10
|
+
|
11
|
+
def interpret(parent, keyword, *args, &block)
|
12
|
+
Glimmer::Opal::Label.new(parent, args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'glimmer/dsl/expression'
|
2
|
+
|
3
|
+
module Glimmer
|
4
|
+
module DSL
|
5
|
+
module Opal
|
6
|
+
class PropertyExpression < StaticExpression
|
7
|
+
include TopLevelExpression
|
8
|
+
|
9
|
+
def can_interpret?(parent, keyword, *args, &block)
|
10
|
+
keyword.to_s == 'text'
|
11
|
+
end
|
12
|
+
|
13
|
+
def interpret(parent, keyword, *args, &block)
|
14
|
+
parent.text = args.first.to_s
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'glimmer/dsl/static_expression'
|
2
|
+
require 'glimmer/dsl/top_level_expression'
|
3
|
+
require 'glimmer/dsl/parent_expression'
|
4
|
+
require 'glimmer/opal/shell'
|
5
|
+
|
6
|
+
module Glimmer
|
7
|
+
module DSL
|
8
|
+
module Opal
|
9
|
+
class ShellExpression < StaticExpression
|
10
|
+
include TopLevelExpression
|
11
|
+
include ParentExpression
|
12
|
+
|
13
|
+
def interpret(parent, keyword, *args, &block)
|
14
|
+
Glimmer::Opal::Shell.new(args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
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
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Glimmer
|
2
|
+
module Opal
|
3
|
+
class Label
|
4
|
+
attr_reader :text
|
5
|
+
|
6
|
+
def initialize(parent, args)
|
7
|
+
@parent = parent
|
8
|
+
@args = args
|
9
|
+
@parent.add_child(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
def text=(value)
|
13
|
+
@text = value
|
14
|
+
redraw
|
15
|
+
end
|
16
|
+
|
17
|
+
def redraw
|
18
|
+
old_dom = @dom
|
19
|
+
@dom = nil
|
20
|
+
old_dom.replace dom
|
21
|
+
end
|
22
|
+
|
23
|
+
def dom
|
24
|
+
label_text = @text
|
25
|
+
@dom ||= DOM {
|
26
|
+
label label_text
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Glimmer
|
2
|
+
module Opal
|
3
|
+
class Shell
|
4
|
+
def initialize(args)
|
5
|
+
@args = args
|
6
|
+
@children = []
|
7
|
+
$document.ready do
|
8
|
+
$document.body.replace(dom)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def text
|
13
|
+
$document.title
|
14
|
+
end
|
15
|
+
|
16
|
+
def text=(value)
|
17
|
+
$document.title = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_child(child)
|
21
|
+
return if @children.include?(child)
|
22
|
+
@children << child
|
23
|
+
dom << child.dom
|
24
|
+
end
|
25
|
+
|
26
|
+
def dom
|
27
|
+
@dom ||= DOM {
|
28
|
+
body {
|
29
|
+
}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def open
|
34
|
+
# No Op (just a placeholder since it is not needed on the web)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: glimmer-dsl-opal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- AndyMaleh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-06-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: glimmer
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.9.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.9.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec-mocks
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.5.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.5.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.5.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.5.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: puts_debuggerer
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.8.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 10.1.0
|
76
|
+
- - "<"
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 14.0.0
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 10.1.0
|
86
|
+
- - "<"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 14.0.0
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: jeweler
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 2.3.9
|
96
|
+
- - "<"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 3.0.0
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: 2.3.9
|
106
|
+
- - "<"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: 3.0.0
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: rdoc
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 6.2.1
|
116
|
+
- - "<"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 7.0.0
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 6.2.1
|
126
|
+
- - "<"
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: 7.0.0
|
129
|
+
- !ruby/object:Gem::Dependency
|
130
|
+
name: opal-rspec
|
131
|
+
requirement: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - "~>"
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: 0.7.1
|
136
|
+
type: :development
|
137
|
+
prerelease: false
|
138
|
+
version_requirements: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - "~>"
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 0.7.1
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
name: opal-browser
|
145
|
+
requirement: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - "~>"
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 0.2.0
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - "~>"
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: 0.2.0
|
157
|
+
description: Glimmer DSL for Opal (Web GUI Adapter for Desktop Apps)
|
158
|
+
email: andy.am@gmail.com
|
159
|
+
executables: []
|
160
|
+
extensions: []
|
161
|
+
extra_rdoc_files:
|
162
|
+
- CHANGELOG.md
|
163
|
+
- LICENSE.txt
|
164
|
+
- README.md
|
165
|
+
files:
|
166
|
+
- CHANGELOG.md
|
167
|
+
- LICENSE.txt
|
168
|
+
- README.md
|
169
|
+
- VERSION
|
170
|
+
- lib/glimmer-dsl-opal.rb
|
171
|
+
- lib/glimmer/config.rb
|
172
|
+
- lib/glimmer/dsl/engine.rb
|
173
|
+
- lib/glimmer/dsl/expression.rb
|
174
|
+
- lib/glimmer/dsl/expression_handler.rb
|
175
|
+
- lib/glimmer/dsl/opal/dsl.rb
|
176
|
+
- lib/glimmer/dsl/opal/label_expression.rb
|
177
|
+
- lib/glimmer/dsl/opal/property_expression.rb
|
178
|
+
- lib/glimmer/dsl/opal/shell_expression.rb
|
179
|
+
- lib/glimmer/dsl/parent_expression.rb
|
180
|
+
- lib/glimmer/dsl/static_expression.rb
|
181
|
+
- lib/glimmer/dsl/top_level_expression.rb
|
182
|
+
- lib/glimmer/error.rb
|
183
|
+
- lib/glimmer/invalid_keyword_error.rb
|
184
|
+
- lib/glimmer/opal/label.rb
|
185
|
+
- lib/glimmer/opal/shell.rb
|
186
|
+
homepage: http://github.com/AndyObtiva/glimmer-dsl-opal
|
187
|
+
licenses:
|
188
|
+
- MIT
|
189
|
+
metadata: {}
|
190
|
+
post_install_message:
|
191
|
+
rdoc_options: []
|
192
|
+
require_paths:
|
193
|
+
- lib
|
194
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
195
|
+
requirements:
|
196
|
+
- - ">="
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: '0'
|
199
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - ">="
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '0'
|
204
|
+
requirements: []
|
205
|
+
rubygems_version: 3.1.2
|
206
|
+
signing_key:
|
207
|
+
specification_version: 4
|
208
|
+
summary: Glimmer DSL for Opal
|
209
|
+
test_files: []
|