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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c67def84181cab028446e3087c2c22d091bb0b17d02aa91e3948a8d7b176113
4
- data.tar.gz: a2613dc9b58d1ef2d048b93f695e2aef799b06c46ec85999a78ecb48a6c5d469
3
+ metadata.gz: 4e5e05e1e5ce6544e9c0286a46f5436c82ff92e8659044b31794d3f4d9db40f2
4
+ data.tar.gz: 3ad9c659f81fed05328533f1af05713939d44297693af78d78799006009cad71
5
5
  SHA512:
6
- metadata.gz: cbab9c4d0212aa47f46dd73394c05a47ebb95d1b18afb1b76b7400c72ae188f849776f411e3808b3fbd75537d3c7ca416fe3bcf90c08aba17e3058a8bccbc228
7
- data.tar.gz: f913e477fa27d42e46614470e3e9e3c18fafd08e2a8fb6eb65c579b6a5894884e61da5203fc0df1d41fd4860f5dc4b435c123c6b5822a4056f6c01bfb4854ff2
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 JRuby DSL that enables productive and efficient authoring of desktop application user-interfaces while relying on the robust Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support to greatly facilitate synchronizing the GUI with domain models. As a result, that 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.
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 `samples/hello/hello_world.rb`):
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 `samples/elaborate/tic_tac_toe.rb`):
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
- 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)
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 - 10 (find at [https://www.oracle.com/java/technologies/javase-downloads.html](https://www.oracle.com/java/technologies/javase-downloads.html))
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.0
1
+ 0.10.1
@@ -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
- if method_symbol.to_s.match(REGEX_METHODS_EXCLUDED)
53
- raise ExcludedKeywordError, "Glimmer excluded keyword: #{method_symbol}"
54
- end
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
- if !method_symbol.to_s.match(REGEX_METHODS_EXCLUDED)
62
- Glimmer::Config.logger.error {e.message}
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
@@ -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
@@ -38,7 +38,7 @@ module Glimmer
38
38
  end
39
39
 
40
40
  def notify_observers
41
- property_observer_list.each {|observer| observer.call}
41
+ property_observer_list.to_a.each(&:call)
42
42
  end
43
43
 
44
44
  def <<(element)
@@ -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 {|observer| observer.call(send(property_name))}
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 do |thedependent|
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 do |registration|
101
- registration.unregister
102
- end
99
+ registrations.each(&:unregister)
103
100
  end
104
101
  alias unobserve_all_observables unregister_all_observables
105
102
 
@@ -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.debug {"Adding dynamic expression: #{expression.class.name}"}
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.debug {"Adding static expression: #{static_expression.class.name}"}
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.debug {"#{static_expression.class.name} will handle expression keyword #{keyword}"}
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.debug {"Attempting to handle #{keyword} with #{@expression.class.name.split(":").last}"}
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.debug {"#{@expression.class.name} will handle expression keyword #{keyword}"}
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.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-07-22 00:00:00.000000000 Z
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