glimmer 0.10.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +133 -20
- data/VERSION +1 -1
- data/lib/glimmer.rb +6 -12
- data/lib/glimmer/config.rb +15 -0
- data/lib/glimmer/data_binding/observable_array.rb +1 -1
- data/lib/glimmer/data_binding/observable_model.rb +3 -1
- data/lib/glimmer/data_binding/observer.rb +3 -6
- data/lib/glimmer/dsl/engine.rb +3 -3
- data/lib/glimmer/dsl/expression_handler.rb +2 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e5e05e1e5ce6544e9c0286a46f5436c82ff92e8659044b31794d3f4d9db40f2
|
4
|
+
data.tar.gz: 3ad9c659f81fed05328533f1af05713939d44297693af78d78799006009cad71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 674f6f7ea6cf2908261b83ce3580b770bb39ac47c1069c2b26651c897d109863516349d7b09d94199c928b2efceb19719d41123453caa7fde187127bb0c3b16a
|
7
|
+
data.tar.gz: c5d22e44fa047b35f5aadb232f446cc074873dbb4b8638b2f83038208ae0e32535e0668cd19419994d76d1aac95e7a917b711cc8853d589ac3757e9ca90e350c
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
|
9
9
|
(The Original Glimmer Library Since 2007. Beware of Imitators!)
|
10
10
|
|
11
|
-
Glimmer is a native-GUI cross-platform desktop development library written in Ruby. Glimmer's main innovation is a
|
11
|
+
[**Glimmer**](https://rubygems.org/gems/glimmer) is a native-GUI cross-platform desktop development library written in [JRuby](https://www.jruby.org/), a highly portable faster version of [Ruby](https://www.ruby-lang.org/en/). [**Glimmer**](https://rubygems.org/gems/glimmer)'s main innovation is a declarative [Ruby DSL](#glimmer-dsl-syntax) that enables productive and efficient authoring of desktop application user-interfaces while relying on the robust [Eclipse SWT library](https://www.eclipse.org/swt/). [**Glimmer**](https://rubygems.org/gems/glimmer) additionally innovates by having built-in [data-binding](#data-binding) support, which greatly facilitates synchronizing the GUI with domain models. This achieves true decoupling of object oriented components, enabling developers to solve business problems without worrying about GUI concerns or alternatively drive development GUI-first and then write clean business models test-first afterwards. To get started quickly, [Glimmer](https://rubygems.org/gems/glimmer) offers [scaffolding](#scaffolding) options for [Apps](#in-production), [Gems](#custom-shell-gem), and [Custom Widgets](#custom-widgets). Last but not least, [Glimmer](https://rubygems.org/gems/glimmer) includes native-executable [packaging](#packaging--distribution) support, sorely lacking in competing libraries, thus enabling delivery of desktop apps written in [Ruby](https://www.ruby-lang.org/en/) as truly native DMG/PKG/APP files on the [Mac](https://www.apple.com/ca/macos) + [App Store](https://developer.apple.com/macos/distribution/) and MSI/EXE files on [Windows](https://www.microsoft.com/en-ca/windows). Given that [JRuby](https://www.jruby.org/) runs on the [JVM](https://java.com/en/download/faq/whatis_java.xml) (Java Virtual Machine), unlike competing libraries like TK, it does not require recompilation of [Ruby](https://www.ruby-lang.org/en/) to use native GUI libraries on every platform. [Glimmer](https://rubygems.org/gems/glimmer) runs native GUI out of the box on every platform thanks to the [JVM](https://java.com/en/download/faq/whatis_java.xml) and [Eclipse SWT library](https://www.eclipse.org/swt/).
|
12
12
|
|
13
13
|
[<img src="https://covers.oreillystatic.com/images/9780596519650/lrg.jpg" width=105 /><br />
|
14
14
|
Featured in<br />JRuby Cookbook](http://shop.oreilly.com/product/9780596519650.do)
|
@@ -23,7 +23,7 @@ Glimmer DSL gems:
|
|
23
23
|
|
24
24
|
### Hello, World!
|
25
25
|
|
26
|
-
Glimmer code (from
|
26
|
+
Glimmer code (from [samples/hello/hello_world.rb](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/samples/hello/hello_world.rb)):
|
27
27
|
```ruby
|
28
28
|
include Glimmer
|
29
29
|
|
@@ -46,28 +46,28 @@ Glimmer app:
|
|
46
46
|
|
47
47
|
### Tic Tac Toe
|
48
48
|
|
49
|
-
Glimmer code (from
|
49
|
+
Glimmer code (from [samples/elaborate/tic_tac_toe.rb](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/samples/elaborate/tic_tac_toe.rb)):
|
50
50
|
|
51
51
|
```ruby
|
52
52
|
# ...
|
53
|
-
shell {
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
53
|
+
@shell = shell {
|
54
|
+
text "Tic-Tac-Toe"
|
55
|
+
composite {
|
56
|
+
grid_layout 3, true
|
57
|
+
(1..3).each { |row|
|
58
|
+
(1..3).each { |column|
|
59
|
+
button {
|
60
|
+
layout_data :fill, :fill, true, true
|
61
|
+
text bind(@tic_tac_toe_board[row, column], :sign)
|
62
|
+
enabled bind(@tic_tac_toe_board[row, column], :empty)
|
63
|
+
on_widget_selected {
|
64
|
+
@tic_tac_toe_board.mark(row, column)
|
65
|
+
}
|
66
|
+
}
|
65
67
|
}
|
66
68
|
}
|
67
69
|
}
|
68
70
|
}
|
69
|
-
}
|
70
|
-
}
|
71
71
|
# ...
|
72
72
|
```
|
73
73
|
|
@@ -81,6 +81,96 @@ Glimmer app:
|
|
81
81
|
|
82
82
|
![Tic Tac Toe](images/glimmer-tic-tac-toe-in-progress.png)
|
83
83
|
|
84
|
+
### Contact Manager
|
85
|
+
|
86
|
+
Glimmer code (from [samples/elaborate/contact_manager.rb](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/samples/elaborate/contact_manager.rb)):
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
# ...
|
90
|
+
shell {
|
91
|
+
text "Contact Manager"
|
92
|
+
composite {
|
93
|
+
composite {
|
94
|
+
grid_layout 2, false
|
95
|
+
label {text "First &Name: "}
|
96
|
+
text {
|
97
|
+
text bind(@contact_manager_presenter, :first_name)
|
98
|
+
on_key_pressed {|key_event|
|
99
|
+
@contact_manager_presenter.find if key_event.keyCode == swt(:cr)
|
100
|
+
}
|
101
|
+
}
|
102
|
+
label {text "&Last Name: "}
|
103
|
+
text {
|
104
|
+
text bind(@contact_manager_presenter, :last_name)
|
105
|
+
on_key_pressed {|key_event|
|
106
|
+
@contact_manager_presenter.find if key_event.keyCode == swt(:cr)
|
107
|
+
}
|
108
|
+
}
|
109
|
+
label {text "&Email: "}
|
110
|
+
text {
|
111
|
+
text bind(@contact_manager_presenter, :email)
|
112
|
+
on_key_pressed {|key_event|
|
113
|
+
@contact_manager_presenter.find if key_event.keyCode == swt(:cr)
|
114
|
+
}
|
115
|
+
}
|
116
|
+
composite {
|
117
|
+
grid_layout 2, false
|
118
|
+
button {
|
119
|
+
text "&Find"
|
120
|
+
on_widget_selected {
|
121
|
+
@contact_manager_presenter.find
|
122
|
+
}
|
123
|
+
}
|
124
|
+
button {
|
125
|
+
text "&List All"
|
126
|
+
on_widget_selected {
|
127
|
+
@contact_manager_presenter.list
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
table(:multi) { |table_proxy|
|
134
|
+
layout_data {
|
135
|
+
horizontal_alignment :fill
|
136
|
+
vertical_alignment :fill
|
137
|
+
grab_excess_horizontal_space true
|
138
|
+
grab_excess_vertical_space true
|
139
|
+
height_hint 200
|
140
|
+
}
|
141
|
+
table_column {
|
142
|
+
text "First Name"
|
143
|
+
width 80
|
144
|
+
}
|
145
|
+
table_column {
|
146
|
+
text "Last Name"
|
147
|
+
width 80
|
148
|
+
}
|
149
|
+
table_column {
|
150
|
+
text "Email"
|
151
|
+
width 200
|
152
|
+
}
|
153
|
+
items bind(@contact_manager_presenter, :results),
|
154
|
+
column_properties(:first_name, :last_name, :email)
|
155
|
+
on_mouse_up { |event|
|
156
|
+
table_proxy.edit_table_item(event.table_item, event.column_index)
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}
|
160
|
+
}.open
|
161
|
+
# ...
|
162
|
+
```
|
163
|
+
|
164
|
+
Run:
|
165
|
+
|
166
|
+
```
|
167
|
+
glimmer samples/elaborate/contact_manager.rb
|
168
|
+
```
|
169
|
+
|
170
|
+
Glimmer App:
|
171
|
+
|
172
|
+
![Contact Manager](images/glimmer-contact-manager.png)
|
173
|
+
|
84
174
|
NOTE: Glimmer is in beta mode. Please help make better by [contributing](#contributing), adopting for small or low risk projects, and providing feedback.
|
85
175
|
|
86
176
|
## Table of contents
|
@@ -175,7 +265,7 @@ NOTE: Glimmer is in beta mode. Please help make better by [contributing](#contri
|
|
175
265
|
- [Elaborate Samples](#elaborate-samples)
|
176
266
|
- [Login](#login)
|
177
267
|
- [Tic Tac Toe Sample](#tic-tac-toe-sample)
|
178
|
-
- [Contact Manager](#contact-manager)
|
268
|
+
- [Contact Manager](#contact-manager-sample)
|
179
269
|
- [External Samples](#external-samples)
|
180
270
|
- [Glimmer Calculator](#glimmer-calculator)
|
181
271
|
- [Gladiator](#gladiator)
|
@@ -225,7 +315,7 @@ https://www.eclipse.org/swt/faq.php
|
|
225
315
|
|
226
316
|
- SWT 4.15 (comes included in Glimmer gem)
|
227
317
|
- JRuby 9.2.12.0 (supporting Ruby 2.5.x syntax) (find at [https://www.jruby.org/download](https://www.jruby.org/download))
|
228
|
-
- JDK 8
|
318
|
+
- JDK 8 (find at [https://www.oracle.com/java/technologies/javase-downloads.html](https://www.oracle.com/java/technologies/javase-downloads.html))
|
229
319
|
- (Optional) RVM is needed for [Scaffolding](#scaffolding) only (find at [https://rvm.io/](https://rvm.io/))
|
230
320
|
|
231
321
|
On **Mac** and **Linux**, an easy way to obtain JRuby is through [RVM](http://rvm.io) by running:
|
@@ -2540,6 +2630,29 @@ The max limit can be changed via the `Glimmer::Config::loop_max_count=(count)` c
|
|
2540
2630
|
|
2541
2631
|
Infinite loop detection may be disabled altogether if needed by setting `Glimmer::Config::loop_max_count` to `-1`
|
2542
2632
|
|
2633
|
+
### excluded_keyword_checkers
|
2634
|
+
|
2635
|
+
Glimmer permits consumers to exclude keywords from DSL processing by its engine via the `excluded_keyword_checkers` config option.
|
2636
|
+
|
2637
|
+
To do so, add a proc to it that returns a boolean indicating if a keyword is excluded or not.
|
2638
|
+
|
2639
|
+
Note that this proc runs within the context of the Glimmer object (as in the object mixing in the Glimmer module), so checker can can pretend to run there with its `self` object assumption.
|
2640
|
+
|
2641
|
+
Example of keywords excluded by [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt):
|
2642
|
+
|
2643
|
+
```ruby
|
2644
|
+
Glimmer::Config.excluded_keyword_checkers << lambda do |method_symbol, *args|
|
2645
|
+
method = method_symbol.to_s
|
2646
|
+
result = false
|
2647
|
+
result ||= method.start_with?('on_swt_') && is_a?(Glimmer::UI::CustomWidget) && respond_to?(method)
|
2648
|
+
result ||= method == 'dispose' && is_a?(Glimmer::UI::CustomWidget) && respond_to?(method)
|
2649
|
+
result ||= ['drag_source_proxy', 'drop_target_proxy'].include?(method) && is_a?(Glimmer::UI::CustomWidget)
|
2650
|
+
result ||= method == 'post_initialize_child'
|
2651
|
+
result ||= method.end_with?('=')
|
2652
|
+
result ||= ['finish_edit!', 'search', 'all_tree_items', 'depth_first_search'].include?(method) && is_a?(Glimmer::UI::CustomWidget) && body_root.respond_to?(method)
|
2653
|
+
end
|
2654
|
+
```
|
2655
|
+
|
2543
2656
|
## Glimmer Style Guide
|
2544
2657
|
|
2545
2658
|
- Widgets are declared with underscored lowercase versions of their SWT names minus the SWT package name.
|
@@ -2819,7 +2932,7 @@ glimmer samples/elaborate/tic_tac_toe.rb
|
|
2819
2932
|
![Tic Tac Toe In Progress](images/glimmer-tic-tac-toe-in-progress.png)
|
2820
2933
|
![Tic Tac Toe Game Over](images/glimmer-tic-tac-toe-game-over.png)
|
2821
2934
|
|
2822
|
-
#### Contact Manager
|
2935
|
+
#### Contact Manager Sample
|
2823
2936
|
|
2824
2937
|
This sample demonstrates table data-binding, sorting, filtering, GUI layout, MVP pattern, and test-driven development (has [specs](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/spec/samples/elaborate/contact_manager/contact_manager_presenter_spec.rb)).
|
2825
2938
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.1
|
data/lib/glimmer.rb
CHANGED
@@ -17,7 +17,6 @@ require 'glimmer/config'
|
|
17
17
|
# Glimmer DSL dynamic keywords (e.g. label, combo, etc...) are available via method_missing
|
18
18
|
module Glimmer
|
19
19
|
#TODO make it configurable to include or not include perhaps reverting to using included
|
20
|
-
REGEX_METHODS_EXCLUDED = /^(to_|\[)/
|
21
20
|
|
22
21
|
# TODO add loop detection support to avoid infinite loops (perhaps breaks after 3 repetitions and provides an option to allow it if intentional)
|
23
22
|
class << self
|
@@ -41,27 +40,22 @@ module Glimmer
|
|
41
40
|
new_loop_data = [method_symbol, args, block]
|
42
41
|
if new_loop_data == Glimmer.loop_last_data
|
43
42
|
Glimmer.loop_increment!
|
44
|
-
if Glimmer.loop == Config.loop_max_count
|
45
|
-
raise "Glimmer looped #{Config.loop_max_count} times with keyword '#{new_loop_data[0]}'! Check code for errors."
|
46
|
-
end
|
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
|
47
44
|
else
|
48
45
|
Glimmer.loop_reset!
|
49
46
|
end
|
50
47
|
Glimmer.loop_last_data = new_loop_data
|
51
48
|
# This if statement speeds up Glimmer in girb or whenever directly including on main object
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
Glimmer::Config.logger.debug {"Interpreting keyword: #{method_symbol}"}
|
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}"}
|
56
52
|
Glimmer::DSL::Engine.interpret(method_symbol, *args, &block)
|
57
53
|
rescue ExcludedKeywordError => e
|
58
54
|
# TODO add a feature to show excluded keywords optionally for debugging purposes
|
59
55
|
super(method_symbol, *args, &block)
|
60
56
|
rescue InvalidKeywordError => e
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
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}
|
65
59
|
super(method_symbol, *args, &block)
|
66
60
|
end
|
67
61
|
end
|
data/lib/glimmer/config.rb
CHANGED
@@ -2,9 +2,24 @@ module Glimmer
|
|
2
2
|
module Config
|
3
3
|
class << self
|
4
4
|
LOOP_MAX_COUNT_DEFAULT = 100
|
5
|
+
REGEX_METHODS_EXCLUDED = /^(to_|\[)/
|
5
6
|
|
6
7
|
attr_writer :loop_max_count
|
7
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
|
+
|
8
23
|
def loop_max_count
|
9
24
|
@loop_max_count ||= LOOP_MAX_COUNT_DEFAULT
|
10
25
|
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
|
|
@@ -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
@@ -96,7 +96,7 @@ module Glimmer
|
|
96
96
|
dynamic_expression_chains_of_responsibility[dsl] = expression_names.reverse.map do |expression_name|
|
97
97
|
expression_class(dsl_namespace, expression_name).new
|
98
98
|
end.reduce(nil) do |last_expresion_handler, expression|
|
99
|
-
Glimmer::Config.logger.
|
99
|
+
Glimmer::Config.logger.info {"Adding dynamic expression: #{expression.class.name}"}
|
100
100
|
expression_handler = ExpressionHandler.new(expression)
|
101
101
|
expression_handler.next = last_expresion_handler if last_expresion_handler
|
102
102
|
expression_handler
|
@@ -104,7 +104,7 @@ module Glimmer
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def add_static_expression(static_expression)
|
107
|
-
Glimmer::Config.logger.
|
107
|
+
Glimmer::Config.logger.info {"Adding static expression: #{static_expression.class.name}"}
|
108
108
|
keyword = static_expression.class.keyword
|
109
109
|
static_expression_dsl = static_expression.class.dsl
|
110
110
|
static_expressions[keyword] ||= {}
|
@@ -132,7 +132,7 @@ module Glimmer
|
|
132
132
|
if !static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block)
|
133
133
|
raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent}"
|
134
134
|
else
|
135
|
-
Glimmer::Config.logger.
|
135
|
+
Glimmer::Config.logger.info {"#{static_expression.class.name} will handle expression keyword #{keyword}"}
|
136
136
|
static_expression.interpret(Glimmer::DSL::Engine.parent, keyword, *args, &block).tap do |ui_object|
|
137
137
|
Glimmer::DSL::Engine.add_content(ui_object, static_expression, &block) unless block.nil?
|
138
138
|
Glimmer::DSL::Engine.dsl_stack.pop
|
@@ -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.10.
|
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-07-
|
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
|