glimmer-dsl-libui 0.4.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7787d307fad4098e8f050a94c6477e9fca1f6cc8a2af4f2c16126a0a118dbc59
4
- data.tar.gz: 0cc3d91a91ec96fa4bfecebef3829f4dc384f51aae7a81157385812d1aac2e8b
3
+ metadata.gz: 979ea7d60d873acdbe09e6ae2ceb48318798fa41ed13bb3a6bc8dcb642933165
4
+ data.tar.gz: 7cc05757477a0a42b85a20a6b298c147b5fba948f9e1eedd21701ab392a2d78a
5
5
  SHA512:
6
- metadata.gz: 89d886d203a00b83b7a1b5640dfb83f256b6514586b254bb4b00157c88df29acaa80b30194909f62858d6c79eba1782a7d4deda143d5406bd5048899f3d9835c
7
- data.tar.gz: c94709151900aac23b7148422ee96d484413437b57a78aca7ece2948b6a48a3db3cca7c64827ade37037f9d4af27cce0e6f0bf0a2498358afd07a279595dec12
6
+ metadata.gz: 8feb498d6d9eae22df82c9c9e2b0bd12ef11eb1ec9e4f90ac94f7151be28225f7dce775b8352b25ef98e4bc36f2aedd56370a1265a313f0997161396034f16d0
7
+ data.tar.gz: f76393bfebc577d9ce5e5add450ee70e337b67e7a63be24f5f91e4180d65c0d72c7236680f5843c446161710961ec51aa6520f037fcdcc0fc617d21ac182b850
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.4.1
4
+
5
+ - Document `observe` keyword
6
+ - Document unidirectional data-binding in more detail (like `:before_read`, `:on_read`, and `:after_read` options)
7
+ - Simplify examples/tetris.rb with `observe` keyword
8
+ - Simplify examples/method_based_custom_keyword.rb with `observe` keyword
9
+ - Simplify examples/color_the_circles.rb with `observe` keyword
10
+ - Simplify examples/snake.rb with `observe` keyword
11
+
3
12
  ## 0.4.0
4
13
 
5
14
  - Upgrade to LibUI 0.0.13
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.4.0
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.4.1
2
2
  ## Prerequisite-Free Ruby Desktop Development GUI Library
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
4
4
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -233,6 +233,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
233
233
  - [Area Transform Matrix](#area-transform-matrix)
234
234
  - [Smart Defaults and Conventions](#smart-defaults-and-conventions)
235
235
  - [Custom Keywords](#custom-keywords)
236
+ - [Observer Pattern](#observer-pattern)
236
237
  - [Data-Binding](#data-binding)
237
238
  - [API Gotchas](#api-gotchas)
238
239
  - [Original API](#original-api)
@@ -371,7 +372,7 @@ gem install glimmer-dsl-libui
371
372
  Or install via Bundler `Gemfile`:
372
373
 
373
374
  ```ruby
374
- gem 'glimmer-dsl-libui', '~> 0.4.0'
375
+ gem 'glimmer-dsl-libui', '~> 0.4.1'
375
376
  ```
376
377
 
377
378
  Add `require 'glimmer-dsl-libui'` at the top, and then `include Glimmer` into the top-level main object for testing or into an actual class for serious usage.
@@ -1321,34 +1322,66 @@ window('Method-Based Custom Keyword') {
1321
1322
 
1322
1323
  ![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
1323
1324
 
1325
+ ### Observer Pattern
1326
+
1327
+ The [Observer Design Pattern](https://en.wikipedia.org/wiki/Observer_pattern) (a.k.a. Observer Pattern) is fundamental to building GUIs (Graphical User Interfaces) following the [MVC (Model View Controller) Architectural Pattern](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) or any of its variations like [MVP (Model View Presenter)](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter). In the original Smalltalk-MVC, the View observes the Model for changes and updates itself accordingly.
1328
+
1329
+ ![MVC - Model View Controller](https://www.researchgate.net/profile/Danny-Weyns/publication/269303611/figure/fig2/AS:858133056462866@1581606272800/Smalltalk80-MVC-pattern-View-and-Controller-work-as-a-pair-allowing-the-user-to-interact.ppm)
1330
+
1331
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) supports the [Observer Design Pattern](https://en.wikipedia.org/wiki/Observer_pattern) via the `observe(model, attribute=nil)` keyword, which can observe `Object` models with attributes, `Hash`es, and `Array`s. It automatically enhances objects as needed to support automatically notifying observers of changes via `observable#notify_observers(attribute)` method:
1332
+ - `Object` becomes `Glimmer::DataBinding::ObservableModel`, which supports observing specified `Object` model attributes.
1333
+ - `Hash` becomes `Glimmer::DataBinding::ObservableHash`, which supports observing all `Hash` keys or a specific `Hash` key
1334
+ - `Array` becomes `Glimmer::DataBinding::ObservableArray`, which supports observing `Array` changes like those done with `push`, `<<`, `delete`, and `map!` methods (all mutation methods).
1335
+
1336
+ Example:
1337
+
1338
+ ```ruby
1339
+ observe(person, :name) do |new_name|
1340
+ @name_label.text = new_name
1341
+ end
1342
+ ```
1343
+
1344
+ That observes a person's name attribute for changes and updates the name `label` `text` property accordingly.
1345
+
1346
+ [Learn about Glimmer's Observer Pattern capabilities and options in more detail at the Glimmer project page.](https://github.com/AndyObtiva/glimmer#data-binding-library)
1347
+
1348
+ See examples of the `observe` keyword at [Color The Circles](#color-the-circles), [Method-Based Custom Keyword](#method-based-custom-keyword), [Snake](#snake), and [Tetris](#tetris).
1349
+
1324
1350
  ### Data-Binding
1325
1351
 
1326
1352
  [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) supports unidirectional (one-way) data-binding of any control/shape/attributed-string property via the `<=` symbol (indicating data is moving from the right side, which is the model, to the left side, which is the GUI view object).
1327
1353
 
1354
+ The data-binding API is more precisely: `view_property <= [model, attribute, *options]`
1355
+
1328
1356
  This is also known as the [Glimmer Shine](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#shine) syntax for data-binding, a [Glimmer](https://github.com/AndyObtiva/glimmer)-only unique innovation.
1329
1357
 
1330
1358
  Example:
1331
1359
 
1332
1360
  ```ruby
1333
- window {
1334
- title <= [@game, :score, on_read: -> (score) {"Glimmer Snake (Score: #{@game.score})"}]
1361
+ square(0, 0, CELL_SIZE) {
1362
+ fill <= [@grid.cells[row][column], :color]
1335
1363
  }
1336
1364
  ```
1337
1365
 
1338
- That is data-binding the `window` `title` property to the `score` attribute of a `@game`, but converting on read from the Model to a `String`.
1366
+ That is data-binding a grid cell color to a `square` shape's `fill` property. That means if the `color` attribute of the grid cell is updated, the `fill` property of the `square` shape is automatically updated accordingly.
1339
1367
 
1340
1368
  Another Example:
1341
1369
 
1342
1370
  ```ruby
1343
- square(0, 0, CELL_SIZE) {
1344
- fill <= [@grid.cells[row][column], :color]
1371
+ window {
1372
+ title <= [@game, :score, on_read: -> (score) {"Glimmer Snake (Score: #{@game.score})"}]
1345
1373
  }
1346
1374
  ```
1347
1375
 
1348
- That is data-binding a grid cell color to a `square` shape's `fill` property. That means if the `color` attribute of the grid cell is updated, the `fill` property of the `square` shape is automatically updated accordingly.
1376
+ That is data-binding the `window` `title` property to the `score` attribute of a `@game`, but converting on read from the Model to a `String`.
1349
1377
 
1350
1378
  Data-binding enables writing very expressive, terse, and declarative code to synchronize View properties with Model attributes instead of pages of imperative code doing the same thing.
1351
1379
 
1380
+ Options include:
1381
+ - `before_read {|value| ...}`: performs an operation before reading data from Model to update the View.
1382
+ - `on_read {|value| ...}`: converts value read from Model to update the View.
1383
+ - `after_read {|converted_value| ...}`: performs an operation after read from Model and updating the View.
1384
+
1352
1385
  Learn more from data-binding usage in [Snake](#snake) and [Tic Tac Toe](#tic_tac_toe) examples.
1353
1386
 
1354
1387
  ### API Gotchas
@@ -4451,7 +4484,8 @@ class ColorTheCircles
4451
4484
  end
4452
4485
 
4453
4486
  def register_observers
4454
- observer = Glimmer::DataBinding::Observer.proc do |new_score|
4487
+ # observe automatically enhances self to become Glimmer::DataBinding::ObservableModel and notify observer block of score attribute changes
4488
+ observe(self, :score) do |new_score|
4455
4489
  Glimmer::LibUI.queue_main do
4456
4490
  @score_label.text = new_score.to_s
4457
4491
  if new_score == -20
@@ -4465,7 +4499,6 @@ class ColorTheCircles
4465
4499
  end
4466
4500
  end
4467
4501
  end
4468
- observer.observe(self, :score) # automatically enhances self to become Glimmer::DataBinding::ObservableModel and notify observer on score attribute changes
4469
4502
  end
4470
4503
 
4471
4504
  def setup_circle_factory
@@ -6282,9 +6315,9 @@ def label_pair(model, attribute, value)
6282
6315
  name_label = label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
6283
6316
  value_label = label(value.to_s)
6284
6317
  }
6285
- Glimmer::DataBinding::Observer.proc do
6318
+ observe(model, attribute) do
6286
6319
  value_label.text = model.send(attribute)
6287
- end.observe(model, attribute)
6320
+ end
6288
6321
  end
6289
6322
 
6290
6323
  def address(address)
@@ -6591,14 +6624,14 @@ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
6591
6624
 
6592
6625
  ```ruby
6593
6626
  require 'glimmer-dsl-libui'
6594
- require 'glimmer/data_binding/observer'
6595
6627
 
6596
6628
  require_relative 'snake/presenter/grid'
6597
6629
 
6598
6630
  class Snake
6631
+ include Glimmer
6632
+
6599
6633
  CELL_SIZE = 15
6600
6634
  SNAKE_MOVE_DELAY = 0.1
6601
- include Glimmer
6602
6635
 
6603
6636
  def initialize
6604
6637
  @game = Model::Game.new
@@ -6644,7 +6677,7 @@ class Snake
6644
6677
  @game.width.times do |column|
6645
6678
  area {
6646
6679
  square(0, 0, CELL_SIZE) {
6647
- fill <= [@grid.cells[row][column], :color]
6680
+ fill <= [@grid.cells[row][column], :color] # data-bind square fill to grid cell color
6648
6681
  }
6649
6682
 
6650
6683
  on_key_up do |area_key_event|
@@ -6739,7 +6772,7 @@ class Tetris
6739
6772
  end
6740
6773
 
6741
6774
  def register_observers
6742
- Glimmer::DataBinding::Observer.proc do |game_over|
6775
+ observe(@game, :game_over) do |game_over|
6743
6776
  if game_over
6744
6777
  @pause_menu_item.enabled = false
6745
6778
  show_game_over_dialog
@@ -6747,11 +6780,11 @@ class Tetris
6747
6780
  @pause_menu_item.enabled = true
6748
6781
  start_moving_tetrominos_down
6749
6782
  end
6750
- end.observe(@game, :game_over)
6783
+ end
6751
6784
 
6752
6785
  Model::Game::PLAYFIELD_HEIGHT.times do |row|
6753
6786
  Model::Game::PLAYFIELD_WIDTH.times do |column|
6754
- Glimmer::DataBinding::Observer.proc do |new_color|
6787
+ observe(@game.playfield[row][column], :color) do |new_color|
6755
6788
  Glimmer::LibUI.queue_main do
6756
6789
  color = Glimmer::LibUI.interpret_color(new_color)
6757
6790
  block = @playfield_blocks[row][column]
@@ -6762,13 +6795,13 @@ class Tetris
6762
6795
  block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
6763
6796
  block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
6764
6797
  end
6765
- end.observe(@game.playfield[row][column], :color)
6798
+ end
6766
6799
  end
6767
6800
  end
6768
6801
 
6769
6802
  Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
6770
6803
  Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
6771
- Glimmer::DataBinding::Observer.proc do |new_color|
6804
+ observe(@game.preview_playfield[row][column], :color) do |new_color|
6772
6805
  Glimmer::LibUI.queue_main do
6773
6806
  color = Glimmer::LibUI.interpret_color(new_color)
6774
6807
  block = @preview_playfield_blocks[row][column]
@@ -6779,27 +6812,27 @@ class Tetris
6779
6812
  block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
6780
6813
  block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
6781
6814
  end
6782
- end.observe(@game.preview_playfield[row][column], :color)
6815
+ end
6783
6816
  end
6784
6817
  end
6785
6818
 
6786
- Glimmer::DataBinding::Observer.proc do |new_score|
6819
+ observe(@game, :score) do |new_score|
6787
6820
  Glimmer::LibUI.queue_main do
6788
6821
  @score_label.text = new_score.to_s
6789
6822
  end
6790
- end.observe(@game, :score)
6823
+ end
6791
6824
 
6792
- Glimmer::DataBinding::Observer.proc do |new_lines|
6825
+ observe(@game, :lines) do |new_lines|
6793
6826
  Glimmer::LibUI.queue_main do
6794
6827
  @lines_label.text = new_lines.to_s
6795
6828
  end
6796
- end.observe(@game, :lines)
6829
+ end
6797
6830
 
6798
- Glimmer::DataBinding::Observer.proc do |new_level|
6831
+ observe(@game, :level) do |new_level|
6799
6832
  Glimmer::LibUI.queue_main do
6800
6833
  @level_label.text = new_level.to_s
6801
6834
  end
6802
- end.observe(@game, :level)
6835
+ end
6803
6836
  end
6804
6837
 
6805
6838
  def menu_bar
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.4.1
@@ -26,7 +26,8 @@ class ColorTheCircles
26
26
  end
27
27
 
28
28
  def register_observers
29
- observer = Glimmer::DataBinding::Observer.proc do |new_score|
29
+ # observe automatically enhances self to become Glimmer::DataBinding::ObservableModel and notify observer block of score attribute changes
30
+ observe(self, :score) do |new_score|
30
31
  Glimmer::LibUI.queue_main do
31
32
  @score_label.text = new_score.to_s
32
33
  if new_score == -20
@@ -40,7 +41,6 @@ class ColorTheCircles
40
41
  end
41
42
  end
42
43
  end
43
- observer.observe(self, :score) # automatically enhances self to become Glimmer::DataBinding::ObservableModel and notify observer on score attribute changes
44
44
  end
45
45
 
46
46
  def setup_circle_factory
@@ -34,9 +34,9 @@ def label_pair(model, attribute, value)
34
34
  name_label = label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
35
35
  value_label = label(value.to_s)
36
36
  }
37
- Glimmer::DataBinding::Observer.proc do
37
+ observe(model, attribute) do
38
38
  value_label.text = model.send(attribute)
39
- end.observe(model, attribute)
39
+ end
40
40
  end
41
41
 
42
42
  def address(address)
@@ -1,10 +1,12 @@
1
- require 'glimmer/data_binding/observer'
1
+ require 'glimmer'
2
2
  require_relative '../model/game'
3
3
  require_relative 'cell'
4
4
 
5
5
  class Snake
6
6
  module Presenter
7
7
  class Grid
8
+ include Glimmer
9
+
8
10
  attr_reader :game, :cells
9
11
 
10
12
  def initialize(game = Model::Game.new)
@@ -14,7 +16,7 @@ class Snake
14
16
  Cell.new(grid: self, row: row, column: column)
15
17
  end
16
18
  end
17
- Glimmer::DataBinding::Observer.proc do |new_vertebrae|
19
+ observe(@game.snake, :vertebrae) do |new_vertebrae|
18
20
  occupied_snake_positions = @game.snake.vertebrae.map {|v| [v.row, v.column]}
19
21
  @cells.each_with_index do |row_cells, row|
20
22
  row_cells.each_with_index do |cell, column|
@@ -27,7 +29,7 @@ class Snake
27
29
  end
28
30
  end
29
31
  end
30
- end.observe(@game.snake, :vertebrae)
32
+ end
31
33
  end
32
34
 
33
35
  def clear
data/examples/snake.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  require 'glimmer-dsl-libui'
2
- require 'glimmer/data_binding/observer'
3
2
 
4
3
  require_relative 'snake/presenter/grid'
5
4
 
6
5
  class Snake
6
+ include Glimmer
7
+
7
8
  CELL_SIZE = 15
8
9
  SNAKE_MOVE_DELAY = 0.1
9
- include Glimmer
10
10
 
11
11
  def initialize
12
12
  @game = Model::Game.new
@@ -52,7 +52,7 @@ class Snake
52
52
  @game.width.times do |column|
53
53
  area {
54
54
  square(0, 0, CELL_SIZE) {
55
- fill <= [@grid.cells[row][column], :color]
55
+ fill <= [@grid.cells[row][column], :color] # data-bind square fill to grid cell color
56
56
  }
57
57
 
58
58
  on_key_up do |area_key_event|
data/examples/tetris.rb CHANGED
@@ -42,7 +42,7 @@ class Tetris
42
42
  end
43
43
 
44
44
  def register_observers
45
- Glimmer::DataBinding::Observer.proc do |game_over|
45
+ observe(@game, :game_over) do |game_over|
46
46
  if game_over
47
47
  @pause_menu_item.enabled = false
48
48
  show_game_over_dialog
@@ -50,11 +50,11 @@ class Tetris
50
50
  @pause_menu_item.enabled = true
51
51
  start_moving_tetrominos_down
52
52
  end
53
- end.observe(@game, :game_over)
53
+ end
54
54
 
55
55
  Model::Game::PLAYFIELD_HEIGHT.times do |row|
56
56
  Model::Game::PLAYFIELD_WIDTH.times do |column|
57
- Glimmer::DataBinding::Observer.proc do |new_color|
57
+ observe(@game.playfield[row][column], :color) do |new_color|
58
58
  Glimmer::LibUI.queue_main do
59
59
  color = Glimmer::LibUI.interpret_color(new_color)
60
60
  block = @playfield_blocks[row][column]
@@ -65,13 +65,13 @@ class Tetris
65
65
  block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
66
66
  block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
67
67
  end
68
- end.observe(@game.playfield[row][column], :color)
68
+ end
69
69
  end
70
70
  end
71
71
 
72
72
  Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
73
73
  Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
74
- Glimmer::DataBinding::Observer.proc do |new_color|
74
+ observe(@game.preview_playfield[row][column], :color) do |new_color|
75
75
  Glimmer::LibUI.queue_main do
76
76
  color = Glimmer::LibUI.interpret_color(new_color)
77
77
  block = @preview_playfield_blocks[row][column]
@@ -82,27 +82,27 @@ class Tetris
82
82
  block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
83
83
  block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
84
84
  end
85
- end.observe(@game.preview_playfield[row][column], :color)
85
+ end
86
86
  end
87
87
  end
88
88
 
89
- Glimmer::DataBinding::Observer.proc do |new_score|
89
+ observe(@game, :score) do |new_score|
90
90
  Glimmer::LibUI.queue_main do
91
91
  @score_label.text = new_score.to_s
92
92
  end
93
- end.observe(@game, :score)
93
+ end
94
94
 
95
- Glimmer::DataBinding::Observer.proc do |new_lines|
95
+ observe(@game, :lines) do |new_lines|
96
96
  Glimmer::LibUI.queue_main do
97
97
  @lines_label.text = new_lines.to_s
98
98
  end
99
- end.observe(@game, :lines)
99
+ end
100
100
 
101
- Glimmer::DataBinding::Observer.proc do |new_level|
101
+ observe(@game, :level) do |new_level|
102
102
  Glimmer::LibUI.queue_main do
103
103
  @level_label.text = new_level.to_s
104
104
  end
105
- end.observe(@game, :level)
105
+ end
106
106
  end
107
107
 
108
108
  def menu_bar
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-libui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh