glimmer 2.1.5 → 2.3.0

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: c73b637dd451b7033852edb1490cf02f68ac49cdfbaa364ba14f4427a5d35253
4
- data.tar.gz: 3c6a2cd64bdf17087150a39427da632912c5c8f2d8a839bb8c6beda90efc1433
3
+ metadata.gz: 04a3036ea66bf774c6c27cf8b248e5658df35ccc3a69998159e43a013d3489e0
4
+ data.tar.gz: 4241bfc406e54c13bbc4357918bf2bfed5a353f63f5200eea6ed60e0f7c84281
5
5
  SHA512:
6
- metadata.gz: 2678b5f34362a5e63de8bfd6951966322b909de0a667e6bf6004d3c78792ea7a9f514cc1159eb84bc257d6152d83f184fb028a718cc6ea5dc8008a777525efdb
7
- data.tar.gz: 7b96445440558cf0a2c97ee2b5b2a55ee9d1a1466d54bc849537d7ca73568faf348f21dfba358a4b8d0722ad629e4462952499c58ded0a99b33eceda16542727
6
+ metadata.gz: ff74a70f8137ce7967d36e47a191ebdf8efbd67e15724449dd9c5b3a9db04d526a3ab00f4ba484d89af71430ed0543217ac7a0722427b47d735baf3ca4adc524
7
+ data.tar.gz: f854ebfc523130f308b289fcf575d782776057f4f2d212332d38eeb719444e0d8d7790d0f7e2824059a9bccea1f22be532e1bd55619ba2e66dd585930d4574f5
data/CHANGELOG.md CHANGED
@@ -3,6 +3,27 @@
3
3
  Related Change Logs:
4
4
  - [glimmer-dsl-swt/CHANGELOG.md](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/CHANGELOG.md)
5
5
 
6
+ ### 2.3.0
7
+
8
+ - Have observing `ObservableArray` automatically notice if any values are nested arrays and observe them for micro-changes (recursively all the way down)
9
+
10
+ ### 2.2.2
11
+
12
+ - Support auto-notifying on `ObservableArray#replace` observed changes
13
+ - Support auto-notifying on `ObservableArray#filter!` observed changes explicitly (even if `filter!` aliases `select!`)
14
+ - Support auto-notifying on `ObservableHash#filter!` observed changes explicitly (even if `filter!` aliases `select!`)
15
+
16
+ ### 2.2.1
17
+
18
+ - Have `ObservableHash` call `notify_observers(key)` upon performing all mutation operations (as expected): `delete`, `delete_if`, `filter!`, `select!`, `keep_if`, `reject!`, `merge!`, `replace`, `shift`, `transform_keys!`, `transform_values!`
19
+ - Fix issue with `Glimmer::DataBinding::Observer.proc {|new_value| ...}.observe(array)` resulting in new_value coming across as `nil when the array is updated
20
+
21
+ ### 2.2.0
22
+
23
+ - New `Glimmer::DataBinding::ObservableHash` support for observing `hash[key]=value` mutations
24
+ - Ensure observed ObservableHash values are enhanced with ObservableHash if they were of type Hash
25
+ - Ensure observed ObservableModel values are enhanced with ObservableHash if they were of type Hash
26
+
6
27
  ### 2.1.5
7
28
 
8
29
  - Upgrade array_include_methods gem to version 1.4.0 (and fix minor version)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- 2.1.5mg src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 style="position: relative; top: 20px;" />](https://rubygems.org/gems/glimmer) Glimmer - DSL Framework for Ruby GUI and More
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 style="position: relative; top: 20px;" />](https://rubygems.org/gems/glimmer) Glimmer - DSL Framework for Ruby GUI and More
2
2
  [![Gem Version](https://badge.fury.io/rb/glimmer.svg)](http://badge.fury.io/rb/glimmer)
3
3
  [![rspec](https://github.com/AndyObtiva/glimmer/workflows/rspec/badge.svg)](https://github.com/AndyObtiva/glimmer/actions?query=workflow%3Arspec)
4
4
  [![Coverage Status](https://coveralls.io/repos/github/AndyObtiva/glimmer/badge.svg?branch=master)](https://coveralls.io/github/AndyObtiva/glimmer?branch=master)
@@ -210,7 +210,7 @@ end
210
210
  ### Setup
211
211
 
212
212
  Follow these steps to author a [Glimmer](https://rubygems.org/gems/glimmer) DSL:
213
- - Add `gem 'glimmer', '~> 2.1.5'` to `Gemfile` and run `bundle` or run `gem install glimmer -v2.1.5` and add `require 'glimmer'`
213
+ - Add `gem 'glimmer', '~> 2.3.0'` to `Gemfile` and run `bundle` or run `gem install glimmer -v2.3.0` and add `require 'glimmer'`
214
214
  - Create `glimmer/dsl/[dsl_name]/dsl.rb`, which requires and adds all dynamic expressions for the [dsl_name] Glimmer DSL module as per the code shown in the previous section (or [Official DSLs](#official-dsls) as examples)
215
215
  - Create `glimmer/dsl/[dsl_name]/[expresion_name]_expresion.rb` for every [expresion_name] expression needed, whether dynamic or static
216
216
 
@@ -949,14 +949,6 @@ The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/gl
949
949
 
950
950
  ###### Hello, World!
951
951
 
952
- Mac
953
-
954
- ![glimmer-dsl-libui-mac-basic-window.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-basic-window.png)
955
-
956
- Linux
957
-
958
- ![glimmer-dsl-libui-linux-basic-window.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-window.png)
959
-
960
952
  ```ruby
961
953
  require 'glimmer-dsl-libui'
962
954
 
@@ -965,27 +957,25 @@ include Glimmer
965
957
  window('hello world').show
966
958
  ```
967
959
 
968
- ###### Basic Button
969
-
970
960
  Mac
971
961
 
972
- ![glimmer-dsl-libui-mac-basic-button.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-basic-button.png)
973
- ![glimmer-dsl-libui-mac-basic-button-msg-box.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-basic-button-msg-box.png)
962
+ ![glimmer-dsl-libui-mac-basic-window.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-basic-window.png)
974
963
 
975
964
  Linux
976
965
 
977
- ![glimmer-dsl-libui-linux-basic-button.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-button.png)
978
- ![glimmer-dsl-libui-linux-basic-button-msg-box.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-button-msg-box.png)
966
+ ![glimmer-dsl-libui-linux-basic-window.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-window.png)
967
+
968
+ ###### Basic Button
979
969
 
980
970
  ```ruby
981
971
  require 'glimmer-dsl-libui'
982
972
 
983
973
  include Glimmer
984
974
 
985
- window('hello world', 300, 200) { |w|
975
+ window('hello world', 300, 200) {
986
976
  button('Button') {
987
977
  on_clicked do
988
- msg_box(w, 'Information', 'You clicked the button')
978
+ msg_box('Information', 'You clicked the button')
989
979
  end
990
980
  }
991
981
 
@@ -995,223 +985,171 @@ window('hello world', 300, 200) { |w|
995
985
  }.show
996
986
  ```
997
987
 
998
- ###### Control Gallery
999
-
1000
988
  Mac
1001
989
 
1002
- ![glimmer-dsl-libui-mac-control-gallery.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-control-gallery.png)
990
+ ![glimmer-dsl-libui-mac-basic-button.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-basic-button.png)
991
+ ![glimmer-dsl-libui-mac-basic-button-msg-box.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-basic-button-msg-box.png)
1003
992
 
1004
993
  Linux
1005
994
 
1006
- ![glimmer-dsl-libui-linux-control-gallery.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-control-gallery.png)
995
+ ![glimmer-dsl-libui-linux-basic-button.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-button.png)
996
+ ![glimmer-dsl-libui-linux-basic-button-msg-box.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-button-msg-box.png)
997
+
998
+ ###### Basic Table Progress Bar
1007
999
 
1008
1000
  ```ruby
1009
1001
  require 'glimmer-dsl-libui'
1010
1002
 
1011
1003
  include Glimmer
1012
1004
 
1013
- menu('File') {
1014
- menu_item('Open') {
1015
- on_clicked do
1016
- file = open_file(MAIN_WINDOW)
1017
- puts file unless file.nil?
1018
- end
1019
- }
1005
+ data = [
1006
+ ['task 1', 0],
1007
+ ['task 2', 15],
1008
+ ['task 3', 100],
1009
+ ['task 4', 75],
1010
+ ['task 5', -1],
1011
+ ]
1020
1012
 
1021
- menu_item('Save') {
1022
- on_clicked do
1023
- file = save_file(MAIN_WINDOW)
1024
- puts file unless file.nil?
1025
- end
1026
- }
1027
-
1028
- quit_menu_item {
1029
- on_clicked do
1030
- puts 'Bye Bye'
1031
- end
1032
- }
1033
-
1034
- preferences_menu_item # Can optionally contain an on_clicked listener
1035
- }
1013
+ window('Task Progress', 300, 200) {
1014
+ vertical_box {
1015
+ table {
1016
+ text_column('Task')
1017
+ progress_bar_column('Progress')
1036
1018
 
1037
- menu('Edit') {
1038
- check_menu_item('Checkable Item_')
1039
- separator_menu_item
1040
- menu_item('Disabled Item_') {
1041
- enabled false
1019
+ cell_rows data # implicit data-binding
1020
+ }
1021
+
1022
+ button('Mark All As Done') {
1023
+ stretchy false
1024
+
1025
+ on_clicked do
1026
+ data.each_with_index do |row_data, row|
1027
+ data[row] = [row_data[0], 100] # automatically updates table due to implicit data-binding
1028
+ end
1029
+ end
1030
+ }
1042
1031
  }
1043
- }
1044
-
1045
- menu('Help') {
1046
- menu_item('Help')
1047
-
1048
- about_menu_item # Can optionally contain an on_clicked listener
1049
- }
1050
-
1051
- MAIN_WINDOW = window('Control Gallery', 600, 500) {
1052
- margined true
1053
-
1054
- on_closing do
1055
- puts 'Bye Bye'
1056
- end
1057
-
1058
- vertical_box {
1059
- horizontal_box {
1060
- group('Basic Controls') {
1061
- vertical_box {
1062
- button('Button') {
1063
- stretchy false
1064
-
1065
- on_clicked do
1066
- msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
1067
- end
1068
- }
1032
+ }.show
1033
+ ```
1069
1034
 
1070
- checkbox('Checkbox') {
1071
- stretchy false
1035
+ Mac
1072
1036
 
1073
- on_toggled do |c|
1074
- checked = c.checked == 1
1075
- MAIN_WINDOW.title = "Checkbox is #{checked}"
1076
- c.text = "I am the checkbox (#{checked})"
1077
- end
1078
- }
1037
+ ![glimmer-dsl-libui-mac-basic-table-progress-bar.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-basic-table-progress-bar.png)
1079
1038
 
1080
- label('Label') { stretchy false }
1039
+ Linux
1081
1040
 
1082
- horizontal_separator { stretchy false }
1041
+ ![glimmer-dsl-libui-linux-basic-table-progress-bar.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-table-progress-bar.png)
1083
1042
 
1084
- date_picker { stretchy false }
1043
+ ###### Area Gallery
1085
1044
 
1086
- time_picker { stretchy false }
1045
+ ```ruby
1046
+ require 'glimmer-dsl-libui'
1087
1047
 
1088
- date_time_picker { stretchy false }
1048
+ include Glimmer
1089
1049
 
1090
- font_button { stretchy false }
1050
+ window('Area Gallery', 400, 400) {
1051
+ area {
1052
+ path { # declarative stable path
1053
+ square(0, 0, 100)
1054
+ square(100, 100, 400)
1055
+
1056
+ fill r: 102, g: 102, b: 204
1057
+ }
1058
+ path { # declarative stable path
1059
+ rectangle(0, 100, 100, 400)
1060
+ rectangle(100, 0, 400, 100)
1061
+
1062
+ fill r: 204, g: 102, b: 204
1063
+ }
1064
+ path { # declarative stable path
1065
+ figure(100, 100) {
1066
+ line(100, 400)
1067
+ line(400, 100)
1068
+ line(400, 400)
1091
1069
 
1092
- color_button { stretchy false }
1093
- }
1070
+ closed true
1094
1071
  }
1095
1072
 
1096
- vertical_box {
1097
- group('Numbers') {
1098
- stretchy false
1099
-
1100
- vertical_box {
1101
- spinbox(0, 100) {
1102
- stretchy false
1103
- value 42
1104
-
1105
- on_changed do |s|
1106
- puts "New Spinbox value: #{s.value}"
1107
- end
1108
- }
1109
-
1110
- slider(0, 100) {
1111
- stretchy false
1112
-
1113
- on_changed do |s|
1114
- v = s.value
1115
- puts "New Slider value: #{v}"
1116
- @progress_bar.value = v
1117
- end
1118
- }
1119
-
1120
- @progress_bar = progress_bar { stretchy false }
1121
- }
1122
- }
1123
-
1124
- group('Lists') {
1125
- stretchy false
1126
-
1127
- vertical_box {
1128
- combobox {
1129
- stretchy false
1130
- items 'combobox Item 1', 'combobox Item 2', 'combobox Item 3' # also accepts a single array argument
1131
-
1132
- on_selected do |c|
1133
- puts "New combobox selection: #{c.selected}"
1134
- end
1135
- }
1136
-
1137
- editable_combobox {
1138
- stretchy false
1139
- items 'Editable Item 1', 'Editable Item 2', 'Editable Item 3' # also accepts a single array argument
1140
- }
1073
+ fill r: 202, g: 102, b: 104, a: 0.5
1074
+ stroke r: 0, g: 0, b: 0
1075
+ }
1076
+ path { # declarative stable path
1077
+ figure(0, 0) {
1078
+ bezier(200, 100, 100, 200, 400, 100)
1079
+ bezier(300, 100, 100, 300, 100, 400)
1080
+ bezier(100, 300, 300, 100, 400, 400)
1141
1081
 
1142
- radio_buttons {
1143
- items 'Radio Button 1', 'Radio Button 2', 'Radio Button 3' # also accepts a single array argument
1144
- }
1145
- }
1146
- }
1082
+ closed true
1083
+ }
1147
1084
 
1148
- tab {
1149
- tab_item('Page 1') {
1150
- horizontal_box {
1151
- entry {
1152
- text 'Please enter your feelings'
1085
+ fill r: 202, g: 102, b: 204, a: 0.5
1086
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
1087
+ }
1088
+ path { # declarative stable path
1089
+ arc(200, 200, 90, 0, 360, false)
1153
1090
 
1154
- on_changed do |e|
1155
- puts "Current textbox data: '#{e.text}'"
1156
- end
1157
- }
1158
- }
1159
- }
1160
-
1161
- tab_item('Page 2') {
1162
- horizontal_box
1163
- }
1164
-
1165
- tab_item('Page 3') {
1166
- horizontal_box
1167
- }
1168
- }
1169
- }
1091
+ fill r: 202, g: 102, b: 204, a: 0.5
1092
+ stroke r: 0, g: 0, b: 0, thickness: 2
1170
1093
  }
1094
+
1095
+ on_mouse_event do |area_mouse_event|
1096
+ p area_mouse_event
1097
+ end
1098
+
1099
+ on_mouse_moved do |area_mouse_event|
1100
+ puts 'moved'
1101
+ end
1102
+
1103
+ on_mouse_down do |area_mouse_event|
1104
+ puts 'mouse down'
1105
+ end
1106
+
1107
+ on_mouse_up do |area_mouse_event|
1108
+ puts 'mouse up'
1109
+ end
1110
+
1111
+ on_mouse_drag_started do |area_mouse_event|
1112
+ puts 'drag started'
1113
+ end
1114
+
1115
+ on_mouse_dragged do |area_mouse_event|
1116
+ puts 'dragged'
1117
+ end
1118
+
1119
+ on_mouse_dropped do |area_mouse_event|
1120
+ puts 'dropped'
1121
+ end
1122
+
1123
+ on_mouse_entered do
1124
+ puts 'entered'
1125
+ end
1126
+
1127
+ on_mouse_exited do
1128
+ puts 'exited'
1129
+ end
1130
+
1131
+ on_key_event do |area_key_event|
1132
+ p area_key_event
1133
+ end
1134
+
1135
+ on_key_up do |area_key_event|
1136
+ puts 'key up'
1137
+ end
1138
+
1139
+ on_key_down do |area_key_event|
1140
+ puts 'key down'
1141
+ end
1171
1142
  }
1172
- }
1173
-
1174
- MAIN_WINDOW.show
1143
+ }.show
1175
1144
  ```
1176
1145
 
1177
- ###### Basic Table
1178
-
1179
1146
  Mac
1180
1147
 
1181
- ![glimmer-dsl-libui-mac-basic-table.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-basic-table.png)
1148
+ ![glimmer-dsl-libui-mac-area-gallery.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-area-gallery.png)
1182
1149
 
1183
1150
  Linux
1184
1151
 
1185
- ![glimmer-dsl-libui-linux-basic-table.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-table.png)
1186
-
1187
- ```ruby
1188
- require 'glimmer-dsl-libui'
1189
-
1190
- include Glimmer
1191
-
1192
- data = [
1193
- %w[cat meow],
1194
- %w[dog woof],
1195
- %w[chicken cock-a-doodle-doo],
1196
- %w[hourse neigh],
1197
- %w[cow moo]
1198
- ]
1199
-
1200
- window('Animal sounds', 300, 200) {
1201
- horizontal_box {
1202
- table {
1203
- text_column('Animal')
1204
- text_column('Description')
1205
-
1206
- cell_rows data
1207
- }
1208
- }
1209
-
1210
- on_closing do
1211
- puts 'Bye Bye'
1212
- end
1213
- }.show
1214
- ```
1152
+ ![glimmer-dsl-libui-linux-area-gallery.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-area-gallery.png)
1215
1153
 
1216
1154
  ## Data-Binding Library
1217
1155
 
@@ -1222,12 +1160,13 @@ Glimmer enhances observed models automatically (including array operations like
1222
1160
  This relies mainly on the Observer Design Pattern and the MVP (Model-View-Presenter) Architectural Pattern (a variation on MVC)
1223
1161
 
1224
1162
  These are the main classes concerning data-binding:
1225
- - `Observer`: Provides general observer support including unique registration and deregistration for cleanup and prevention of memory leaks. Main methods concerned are: `call`, `register` (alias: `observe`), and `unregister` (alias: `unobserve` or `deregister`)
1226
- - `Observable`: General super-module for all observables. Main methods concerned are: `add_observer` and `remove_observer`
1227
- - `ObservableModel`: Mixin module for any observable model with observable attributes. In addition to `Observable` methods, it has a `notify_observers` method to be called when changes occur. It automatically enhances all attribute setters (ending with `=`) to notify observers on changes. Also, it automatically handles observing array attributes using `ObservableArray` appropriately so they would notify observers upon array mutation changes.
1228
- - `ObservableArray`: Mixin module for any observable array collection that automatically handles notifying observers upon performing array mutation operations (e.g. `push` or `delete`)
1229
- - `ModelBinding`: a higher-level abstraction that relies on all the other observer/observable classes to support basic data-binding, nested data-binding, and computed data-binding
1230
- - `Shine`: enables highly intuitive and visually expressive syntax to perform bidirectional (two-way) data-binding with `<=>` and unidirectional (one-way) data-binding with `<=`
1163
+ - `Glimmer::DataBinding::Observer`: Provides general observer support including unique registration and deregistration for cleanup and prevention of memory leaks. Main methods concerned are: `call`, `register` (alias: `observe`), and `unregister` (alias: `unobserve` or `deregister`)
1164
+ - `Glimmer::DataBinding::Observable`: General super-module for all observables. Main methods concerned are: `add_observer` and `remove_observer`
1165
+ - `Glimmer::DataBinding::ObservableModel`: Mixin module for any observable model with observable attributes. In addition to `Observable` methods, it has a `notify_observers` method to be called when changes occur. It automatically enhances all attribute setters (ending with `=`) to notify observers on changes. Also, it automatically handles observing array attributes using `ObservableArray` appropriately so they would notify observers upon array mutation changes.
1166
+ - `Glimmer::DataBinding::ObservableArray`: Mixin module for any observable array collection that automatically handles notifying observers upon performing array mutation operations (e.g. `push`, `select!`, or `delete`) recursively (meaning if an array contained arrays and they changed, observers are notified)
1167
+ - `Glimmer::DataBinding::ObservableHash`: Mixin module for any observable hash that automatically handles notifying observers upon performing hash mutation operations (e.g. `hash[key]=value`, `select!`, `merge!`)
1168
+ - `Glimmer::DataBinding::ModelBinding`: a higher-level abstraction that relies on all the other observer/observable classes to support basic data-binding, nested data-binding, and computed data-binding
1169
+ - `Glimmer::DataBinding::Shine`: enables highly intuitive and visually expressive syntax to perform bidirectional (two-way) data-binding with `<=>` and unidirectional (one-way) data-binding with `<=`
1231
1170
 
1232
1171
  You may learn more from [Data-Binding](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#data-binding) and [Observer](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#observer) usage in [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt)
1233
1172
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.5
1
+ 2.3.0
data/glimmer.gemspec CHANGED
@@ -2,17 +2,17 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer 2.1.5 ruby lib
5
+ # stub: glimmer 2.3.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer".freeze
9
- s.version = "2.1.5"
9
+ s.version = "2.3.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["AndyMaleh".freeze]
14
- s.date = "2021-09-26"
15
- s.description = "Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of a DSL Engine and an Observable/Observer/Data-Binding Library. Used in the Glimmer DSL for SWT (JRuby Desktop Development GUI Framework), the Glimmer DSL for Tk (Ruby Desktop Development GUI Library), the Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps), the Glimmer DSL for XML (& HTML), and the Glimmer DSL for CSS.".freeze
14
+ s.date = "2021-10-07"
15
+ s.description = "Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of a DSL Engine and an Observable / Observer / Data-Binding Library (including Observable Model, Observable Array, and Observable Hash). Used in Glimmer DSL for SWT (JRuby Desktop Development GUI Framework), Glimmer DSL for Tk (Ruby Desktop Development GUI Library), Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI Library), Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps), Glimmer DSL for XML (& HTML), and Glimmer DSL for CSS.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.extra_rdoc_files = [
18
18
  "CHANGELOG.md",
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
32
32
  "lib/glimmer/data_binding/model_binding.rb",
33
33
  "lib/glimmer/data_binding/observable.rb",
34
34
  "lib/glimmer/data_binding/observable_array.rb",
35
+ "lib/glimmer/data_binding/observable_hash.rb",
35
36
  "lib/glimmer/data_binding/observable_model.rb",
36
37
  "lib/glimmer/data_binding/observer.rb",
37
38
  "lib/glimmer/data_binding/shine.rb",
@@ -50,7 +51,7 @@ Gem::Specification.new do |s|
50
51
  ]
51
52
  s.homepage = "http://github.com/AndyObtiva/glimmer".freeze
52
53
  s.licenses = ["MIT".freeze]
53
- s.rubygems_version = "3.2.22".freeze
54
+ s.rubygems_version = "3.2.28".freeze
54
55
  s.summary = "Glimmer - DSL Engine for Ruby GUI and More".freeze
55
56
 
56
57
  if s.respond_to? :specification_version then
@@ -198,7 +198,7 @@ module Glimmer
198
198
  end
199
199
  end
200
200
 
201
- def call(value)
201
+ def call(value, *extra_args)
202
202
  return if model.nil?
203
203
  converted_value = value
204
204
  invoke_property_writer(model, "#{property_name}=", converted_value) unless converted_value == evaluate_property
@@ -21,6 +21,7 @@
21
21
 
22
22
  require 'set'
23
23
  require 'glimmer/data_binding/observable'
24
+ require 'glimmer/data_binding/observer'
24
25
  require 'array_include_methods'
25
26
 
26
27
  using ArrayIncludeMethods
@@ -29,6 +30,20 @@ module Glimmer
29
30
  module DataBinding
30
31
  module ObservableArray
31
32
  include Observable
33
+
34
+ class Notifier
35
+ include Observer
36
+
37
+ attr_reader :observable_array
38
+
39
+ def initialize(observable_array)
40
+ @observable_array = observable_array
41
+ end
42
+
43
+ def call(new_value=nil, *extra_args)
44
+ @observable_array.notify_observers
45
+ end
46
+ end
32
47
 
33
48
  def add_observer(observer, *element_properties)
34
49
  element_properties = element_properties.flatten.compact.uniq
@@ -49,6 +64,23 @@ module Glimmer
49
64
  element_properties_for(observer).each do |property|
50
65
  observer.observe(element, property)
51
66
  end
67
+ ensure_array_object_observer(element) if element.is_a?(Array)
68
+ end
69
+
70
+ def ensure_array_object_observer(object)
71
+ return unless object&.is_a?(Array)
72
+ array_object_observer = array_object_observer_for(object)
73
+ array_observer_registration = array_object_observer.observe(object)
74
+ property_observer_list.each do |observer|
75
+ my_registration = observer.registration_for(self)
76
+ observer.add_dependent(my_registration => array_observer_registration)
77
+ end
78
+ end
79
+
80
+ def array_object_observer_for(object)
81
+ @array_object_observers ||= Concurrent::Hash.new
82
+ @array_object_observers[object] = Notifier.new(self) unless @array_object_observers.has_key?(object)
83
+ @array_object_observers[object]
52
84
  end
53
85
 
54
86
  def remove_observer(observer, *element_properties)
@@ -76,6 +108,15 @@ module Glimmer
76
108
  element_properties_for(observer).each do |property|
77
109
  observer.unobserve(element, property)
78
110
  end
111
+ if element.is_a?(ObservableArray)
112
+ array_object_observer_for(element).unobserve(element)
113
+ element.property_observer_list.select {|o| o.observable_array == self}.each do |o|
114
+ o.registrations.each do |registration|
115
+ registration.deregister
116
+ end
117
+ @array_object_observers.reject! {|k, v| v == o}
118
+ end
119
+ end
79
120
  end
80
121
 
81
122
  def has_observer?(observer)
@@ -99,7 +140,7 @@ module Glimmer
99
140
  end
100
141
 
101
142
  def notify_observers
102
- property_observer_list.to_a.each(&:call)
143
+ property_observer_list.to_a.each { |o| o.call(self) }
103
144
  end
104
145
 
105
146
  def <<(element)
@@ -237,6 +278,21 @@ module Glimmer
237
278
  end
238
279
  end
239
280
 
281
+ def filter!(&block)
282
+ if block_given?
283
+ old_array = Array.new(self)
284
+ super(&block).tap do
285
+ (old_array - self).each do |old_value|
286
+ unregister_dependent_observers(old_value)
287
+ remove_element_observers(old_value)
288
+ end
289
+ notify_observers
290
+ end
291
+ else
292
+ super
293
+ end
294
+ end
295
+
240
296
  def shuffle!(hash = nil)
241
297
  (hash.nil? ? super() : super(random: hash[:random])).tap { notify_observers }
242
298
  end
@@ -294,6 +350,17 @@ module Glimmer
294
350
  end
295
351
  end
296
352
 
353
+ def replace(other_array)
354
+ old_array = Array.new(self)
355
+ super(other_array).tap do
356
+ (old_array - self).each do |old_value|
357
+ unregister_dependent_observers(old_value)
358
+ remove_element_observers(old_value)
359
+ end
360
+ notify_observers
361
+ end
362
+ end
363
+
297
364
  def unregister_dependent_observers(old_value)
298
365
  return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
299
366
  property_observer_list.each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
@@ -0,0 +1,375 @@
1
+ # Copyright (c) 2007-2021 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.
21
+
22
+ require 'glimmer/data_binding/observable'
23
+ require 'glimmer/data_binding/observer'
24
+
25
+ module Glimmer
26
+ module DataBinding
27
+ module ObservableHash
28
+ include Observable
29
+
30
+ class Notifier
31
+ include Observer
32
+
33
+ def initialize(observable_model, key)
34
+ @observable_model = observable_model
35
+ @key = key
36
+ end
37
+
38
+ def call(new_value=nil, *extra_args)
39
+ @observable_model.notify_observers(@key)
40
+ end
41
+ end
42
+
43
+ OBSERVED_STORE_METHOD = lambda do |key, value|
44
+ if key_observer_list(key).empty?
45
+ if all_key_observer_list.empty?
46
+ self.send('__original__store', key, value)
47
+ else
48
+ old_value = self[key]
49
+ unregister_dependent_observers(nil, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
50
+ self.send('__original__store', key, value)
51
+ notify_observers(key)
52
+ ensure_array_object_observer(nil, value, old_value)
53
+ ensure_hash_object_observer(nil, value, old_value)
54
+ end
55
+ else
56
+ old_value = self[key]
57
+ unregister_dependent_observers(key, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
58
+ self.send('__original__store', key, value)
59
+ notify_observers(key)
60
+ ensure_array_object_observer(key, value, old_value)
61
+ ensure_hash_object_observer(key, value, old_value)
62
+ end
63
+ end
64
+
65
+ def add_observer(observer, key = nil)
66
+ return observer if has_observer?(observer, key)
67
+ key_observer_list(key) << observer
68
+ add_key_writer_observer(key)
69
+ observer
70
+ end
71
+
72
+ def remove_observer(observer, key = nil)
73
+ if has_observer?(observer, key)
74
+ key_observer_list(key).delete(observer)
75
+ observer.unobserve(self, key)
76
+ end
77
+ end
78
+
79
+ def remove_observers(key)
80
+ key_observer_hash[key].each do |observer|
81
+ remove_observer(observer, key)
82
+ end
83
+ key_observer_hash.delete(key)
84
+ end
85
+
86
+ def remove_all_observers
87
+ all_observers = key_observer_hash.clone
88
+ key_observer_hash.keys.each do |key|
89
+ remove_observers(key)
90
+ end
91
+ key_observer_hash.clear
92
+ all_observers
93
+ end
94
+
95
+ def has_observer?(observer, key = nil)
96
+ key_observer_list(key).include?(observer)
97
+ end
98
+
99
+ def has_observer_for_any_key?(observer)
100
+ key_observer_hash.values.map(&:to_a).reduce(:+).include?(observer)
101
+ end
102
+
103
+ def key_observer_hash
104
+ @key_observers ||= Hash.new
105
+ end
106
+
107
+ def key_observer_list(key)
108
+ key_observer_hash[key] = Concurrent::Set.new unless key_observer_hash[key]
109
+ key_observer_hash[key]
110
+ end
111
+
112
+ def all_key_observer_list
113
+ key_observer_list(nil)
114
+ end
115
+
116
+ def notify_observers(key)
117
+ all_key_observer_list.to_a.each { |observer| observer.call(self[key], key) }
118
+ (key_observer_list(key).to_a - all_key_observer_list.to_a).each { |observer| observer.call(self[key], key) }
119
+ end
120
+
121
+ def add_key_writer_observer(key = nil)
122
+ ensure_array_object_observer(key, self[key])
123
+ ensure_hash_object_observer(key, self[key])
124
+ begin
125
+ method('__original__store')
126
+ rescue
127
+ define_singleton_method('__original__store', store_method)
128
+ define_singleton_method('[]=', &OBSERVED_STORE_METHOD)
129
+ end
130
+ rescue => e
131
+ #ignore writing if no key writer exists
132
+ Glimmer::Config.logger.debug {"No need to observe store method: '[]='\n#{e.message}\n#{e.backtrace.join("\n")}"}
133
+ end
134
+
135
+ def store_method
136
+ self.class.instance_method('[]=') rescue self.method('[]=')
137
+ end
138
+
139
+ def unregister_dependent_observers(key, old_value)
140
+ # TODO look into optimizing this
141
+ return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray) || old_value.is_a?(ObservableHash)
142
+ key_observer_list(key).each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self, key), old_value) }
143
+ end
144
+ alias deregister_dependent_observers unregister_dependent_observers
145
+
146
+ def ensure_array_object_observer(key, object, old_object = nil)
147
+ return unless object&.is_a?(Array)
148
+ array_object_observer = array_object_observer_for(key)
149
+ array_observer_registration = array_object_observer.observe(object)
150
+ key_observer_list(key).each do |observer|
151
+ my_registration = observer.registration_for(self, key) # TODO eliminate repetition
152
+ observer.add_dependent(my_registration => array_observer_registration)
153
+ end
154
+ array_object_observer_for(key).unregister(old_object) if old_object.is_a?(ObservableArray)
155
+ end
156
+
157
+ def array_object_observer_for(key)
158
+ @array_object_observers ||= Concurrent::Hash.new
159
+ @array_object_observers[key] = ObservableModel::Notifier.new(self, key) unless @array_object_observers.has_key?(key)
160
+ @array_object_observers[key]
161
+ end
162
+
163
+ def ensure_hash_object_observer(key, object, old_object = nil)
164
+ return unless object&.is_a?(Hash)
165
+ hash_object_observer = hash_object_observer_for(key)
166
+ hash_observer_registration = hash_object_observer.observe(object)
167
+ key_observer_list(key).each do |observer|
168
+ my_registration = observer.registration_for(self, key) # TODO eliminate repetition
169
+ observer.add_dependent(my_registration => hash_observer_registration)
170
+ end
171
+ hash_object_observer_for(key).unregister(old_object) if old_object.is_a?(ObservableHash)
172
+ end
173
+
174
+ def hash_object_observer_for(key)
175
+ @hash_object_observers ||= Concurrent::Hash.new
176
+ @hash_object_observers[key] = ObservableModel::Notifier.new(self, key) unless @hash_object_observers.has_key?(key)
177
+ @hash_object_observers[key]
178
+ end
179
+
180
+ def delete(key, &block)
181
+ old_value = self[key]
182
+ unless old_value.nil?
183
+ unregister_dependent_observers(key, old_value)
184
+ unregister_dependent_observers(nil, old_value)
185
+ end
186
+ super(key, &block).tap do
187
+ notify_observers(key) unless old_value.nil?
188
+ end
189
+ end
190
+
191
+ def delete_if(&block)
192
+ if block_given?
193
+ old_hash = self.dup
194
+ super(&block).tap do |new_hash|
195
+ deleted_keys = old_hash.keys - new_hash.keys
196
+ deleted_keys.each do |deleted_key|
197
+ deleted_value = old_hash[deleted_key]
198
+ unless deleted_value.nil?
199
+ unregister_dependent_observers(deleted_key, deleted_value)
200
+ unregister_dependent_observers(nil, deleted_value)
201
+ notify_observers(deleted_key)
202
+ end
203
+ end
204
+ end
205
+ else
206
+ super
207
+ end
208
+ end
209
+
210
+ def select!(&block)
211
+ if block_given?
212
+ old_hash = self.dup
213
+ super(&block).tap do |new_hash|
214
+ deleted_keys = old_hash.keys - new_hash.keys
215
+ deleted_keys.each do |deleted_key|
216
+ deleted_value = old_hash[deleted_key]
217
+ unless deleted_value.nil?
218
+ unregister_dependent_observers(deleted_key, deleted_value)
219
+ unregister_dependent_observers(nil, deleted_value)
220
+ notify_observers(deleted_key)
221
+ end
222
+ end
223
+ end
224
+ else
225
+ super
226
+ end
227
+ end
228
+
229
+ def filter!(&block)
230
+ if block_given?
231
+ old_hash = self.dup
232
+ super(&block).tap do |new_hash|
233
+ deleted_keys = old_hash.keys - new_hash.keys
234
+ deleted_keys.each do |deleted_key|
235
+ deleted_value = old_hash[deleted_key]
236
+ unless deleted_value.nil?
237
+ unregister_dependent_observers(deleted_key, deleted_value)
238
+ unregister_dependent_observers(nil, deleted_value)
239
+ notify_observers(deleted_key)
240
+ end
241
+ end
242
+ end
243
+ else
244
+ super
245
+ end
246
+ end
247
+
248
+ def keep_if(&block)
249
+ if block_given?
250
+ old_hash = self.dup
251
+ super(&block).tap do |new_hash|
252
+ deleted_keys = old_hash.keys - new_hash.keys
253
+ deleted_keys.each do |deleted_key|
254
+ deleted_value = old_hash[deleted_key]
255
+ unless deleted_value.nil?
256
+ unregister_dependent_observers(deleted_key, deleted_value)
257
+ unregister_dependent_observers(nil, deleted_value)
258
+ notify_observers(deleted_key)
259
+ end
260
+ end
261
+ end
262
+ else
263
+ super
264
+ end
265
+ end
266
+
267
+ def reject!(&block)
268
+ if block_given?
269
+ old_hash = self.dup
270
+ super(&block).tap do |new_hash|
271
+ deleted_keys = old_hash.keys - new_hash.keys
272
+ deleted_keys.each do |deleted_key|
273
+ deleted_value = old_hash[deleted_key]
274
+ unless deleted_value.nil?
275
+ unregister_dependent_observers(deleted_key, deleted_value)
276
+ unregister_dependent_observers(nil, deleted_value)
277
+ notify_observers(deleted_key)
278
+ end
279
+ end
280
+ end
281
+ else
282
+ super
283
+ end
284
+ end
285
+
286
+ def shift
287
+ old_hash = self.dup
288
+ super.tap do
289
+ new_hash = self
290
+ deleted_keys = old_hash.keys - new_hash.keys
291
+ deleted_keys.each do |deleted_key|
292
+ deleted_value = old_hash[deleted_key]
293
+ unless deleted_value.nil?
294
+ unregister_dependent_observers(deleted_key, deleted_value)
295
+ unregister_dependent_observers(nil, deleted_value)
296
+ notify_observers(deleted_key)
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ def merge!(*other_hashes, &block)
303
+ if other_hashes.empty?
304
+ super
305
+ else
306
+ old_hash = self.dup
307
+ super(*other_hashes, &block).tap do |new_hash|
308
+ changed_keys = other_hashes.map(&:keys).reduce(:+)
309
+ changed_keys.each do |changed_key|
310
+ old_value = old_hash[changed_key]
311
+ if new_hash[changed_key] != old_value
312
+ unregister_dependent_observers(changed_key, old_value)
313
+ unregister_dependent_observers(nil, old_value)
314
+ notify_observers(changed_key)
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
320
+
321
+ def replace(other_hash)
322
+ old_hash = self.dup
323
+ super(other_hash).tap do |new_hash|
324
+ changed_keys = old_hash.keys + new_hash.keys
325
+ changed_keys.each do |changed_key|
326
+ old_value = old_hash[changed_key]
327
+ if new_hash[changed_key] != old_value
328
+ unregister_dependent_observers(changed_key, old_value)
329
+ unregister_dependent_observers(nil, old_value)
330
+ notify_observers(changed_key)
331
+ end
332
+ end
333
+ end
334
+ end
335
+
336
+ def transform_keys!(hash2 = nil, &block)
337
+ if hash2.nil? && block.nil?
338
+ super
339
+ else
340
+ old_hash = self.dup
341
+ result = hash2.nil? ? super(&block) : super(hash2, &block)
342
+ result.tap do |new_hash|
343
+ changed_keys = old_hash.keys + new_hash.keys
344
+ changed_keys.each do |changed_key|
345
+ old_value = old_hash[changed_key]
346
+ if new_hash[changed_key] != old_value
347
+ unregister_dependent_observers(changed_key, old_value)
348
+ unregister_dependent_observers(nil, old_value)
349
+ notify_observers(changed_key)
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end
355
+
356
+ def transform_values!(&block)
357
+ if block_given?
358
+ old_hash = self.dup
359
+ super(&block).tap do |new_hash|
360
+ new_hash.keys.each do |changed_key|
361
+ old_value = old_hash[changed_key]
362
+ if new_hash[changed_key] != old_value
363
+ unregister_dependent_observers(changed_key, old_value)
364
+ unregister_dependent_observers(nil, old_value)
365
+ notify_observers(changed_key)
366
+ end
367
+ end
368
+ end
369
+ else
370
+ super
371
+ end
372
+ end
373
+ end
374
+ end
375
+ end
@@ -35,7 +35,7 @@ module Glimmer
35
35
  @property_name = property_name
36
36
  end
37
37
 
38
- def call(new_value=nil)
38
+ def call(new_value=nil, *extra_args)
39
39
  @observable_model.notify_observers(@property_name)
40
40
  end
41
41
  end
@@ -44,10 +44,11 @@ module Glimmer
44
44
  property_writer_name = "#{property_name}="
45
45
  lambda do |value|
46
46
  old_value = self.send(property_name)
47
- unregister_dependent_observers(property_name, old_value)
47
+ unregister_dependent_observers(property_name, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
48
48
  self.send("__original__#{property_writer_name}", value)
49
49
  notify_observers(property_name)
50
50
  ensure_array_object_observer(property_name, value, old_value)
51
+ ensure_hash_object_observer(property_name, value, old_value)
51
52
  end
52
53
  end
53
54
 
@@ -106,6 +107,7 @@ module Glimmer
106
107
  property_writer_name = "#{property_name}="
107
108
  method(property_writer_name)
108
109
  ensure_array_object_observer(property_name, send(property_name))
110
+ ensure_hash_object_observer(property_name, send(property_name))
109
111
  begin
110
112
  method("__original__#{property_writer_name}")
111
113
  rescue
@@ -141,9 +143,26 @@ module Glimmer
141
143
 
142
144
  def array_object_observer_for(property_name)
143
145
  @array_object_observers ||= Concurrent::Hash.new
144
- @array_object_observers[property_name] = ObservableModel::Notifier.new(self, property_name) unless @array_object_observers.has_key?(property_name)
146
+ @array_object_observers[property_name] = Notifier.new(self, property_name) unless @array_object_observers.has_key?(property_name)
145
147
  @array_object_observers[property_name]
146
148
  end
149
+
150
+ def ensure_hash_object_observer(property_name, object, old_object = nil)
151
+ return unless object&.is_a?(Hash)
152
+ hash_object_observer = hash_object_observer_for(property_name)
153
+ hash_observer_registration = hash_object_observer.observe(object)
154
+ property_observer_list(property_name).each do |observer|
155
+ my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
156
+ observer.add_dependent(my_registration => hash_observer_registration)
157
+ end
158
+ hash_object_observer_for(property_name).unregister(old_object) if old_object.is_a?(ObservableHash)
159
+ end
160
+
161
+ def hash_object_observer_for(property_name)
162
+ @hash_object_observers ||= Concurrent::Hash.new
163
+ @hash_object_observers[property_name] = Notifier.new(self, property_name) unless @hash_object_observers.has_key?(property_name)
164
+ @hash_object_observers[property_name]
165
+ end
147
166
  end
148
167
  end
149
168
  end
@@ -41,8 +41,8 @@ module Glimmer
41
41
  end
42
42
 
43
43
  # Called by observables once updates occur sending in the new_value if any
44
- def call(new_value=nil)
45
- @observer_block.call(new_value)
44
+ def call(new_value=nil, *extra_args)
45
+ @observer_block.call(new_value, *extra_args)
46
46
  end
47
47
  end
48
48
 
@@ -86,6 +86,8 @@ module Glimmer
86
86
  # TODO refactor code to be more smart/polymorphic/automated and honor open/closed principle
87
87
  if observable.is_a?(Array)
88
88
  observable.extend(ObservableArray)
89
+ elsif observable.is_a?(Hash)
90
+ observable.extend(ObservableHash)
89
91
  else
90
92
  observable.extend(ObservableModel)
91
93
  end
@@ -141,7 +143,7 @@ module Glimmer
141
143
  dependents_for(registration).delete(dependent)
142
144
  end
143
145
 
144
- def call(new_value)
146
+ def call(new_value = nil, *extra_args)
145
147
  raise Error, 'Not implemented!'
146
148
  end
147
149
  end
@@ -150,3 +152,4 @@ end
150
152
 
151
153
  require 'glimmer/data_binding/observable_model'
152
154
  require 'glimmer/data_binding/observable_array'
155
+ require 'glimmer/data_binding/observable_hash'
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: 2.1.5
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-26 00:00:00.000000000 Z
11
+ date: 2021-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: array_include_methods
@@ -203,11 +203,12 @@ dependencies:
203
203
  - !ruby/object:Gem::Version
204
204
  version: '0'
205
205
  description: Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of
206
- a DSL Engine and an Observable/Observer/Data-Binding Library. Used in the Glimmer
207
- DSL for SWT (JRuby Desktop Development GUI Framework), the Glimmer DSL for Tk (Ruby
208
- Desktop Development GUI Library), the Glimmer DSL for Opal (Pure Ruby Web GUI and
209
- Auto-Webifier of Desktop Apps), the Glimmer DSL for XML (& HTML), and the Glimmer
210
- DSL for CSS.
206
+ a DSL Engine and an Observable / Observer / Data-Binding Library (including Observable
207
+ Model, Observable Array, and Observable Hash). Used in Glimmer DSL for SWT (JRuby
208
+ Desktop Development GUI Framework), Glimmer DSL for Tk (Ruby Desktop Development
209
+ GUI Library), Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development
210
+ GUI Library), Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop
211
+ Apps), Glimmer DSL for XML (& HTML), and Glimmer DSL for CSS.
211
212
  email: andy.am@gmail.com
212
213
  executables: []
213
214
  extensions: []
@@ -228,6 +229,7 @@ files:
228
229
  - lib/glimmer/data_binding/model_binding.rb
229
230
  - lib/glimmer/data_binding/observable.rb
230
231
  - lib/glimmer/data_binding/observable_array.rb
232
+ - lib/glimmer/data_binding/observable_hash.rb
231
233
  - lib/glimmer/data_binding/observable_model.rb
232
234
  - lib/glimmer/data_binding/observer.rb
233
235
  - lib/glimmer/data_binding/shine.rb
@@ -262,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
262
264
  - !ruby/object:Gem::Version
263
265
  version: '0'
264
266
  requirements: []
265
- rubygems_version: 3.2.22
267
+ rubygems_version: 3.2.28
266
268
  signing_key:
267
269
  specification_version: 4
268
270
  summary: Glimmer - DSL Engine for Ruby GUI and More