glimmer-dsl-libui 0.4.0 → 0.4.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: 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