glimmer-dsl-swt 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,108 +0,0 @@
1
- require 'glimmer'
2
-
3
- require_relative 'observable'
4
- require_relative 'observer'
5
-
6
- module Glimmer
7
- module DataBinding
8
- # TODO prefix utility methods with double-underscore
9
- module ObservableModel
10
- include Observable
11
-
12
- class Notifier
13
- include Observer
14
- def initialize(observable_model, property_name)
15
- @observable_model = observable_model
16
- @property_name = property_name
17
- end
18
- def call(new_value=nil)
19
- @observable_model.notify_observers(@property_name)
20
- end
21
- end
22
-
23
- def add_observer(observer, property_name)
24
- return observer if has_observer?(observer, property_name)
25
- property_observer_list(property_name) << observer
26
- add_property_writer_observers(property_name)
27
- observer
28
- end
29
-
30
- def remove_observer(observer, property_name)
31
- property_observer_list(property_name).delete(observer)
32
- end
33
-
34
- def has_observer?(observer, property_name)
35
- property_observer_list(property_name).include?(observer)
36
- end
37
-
38
- def has_observer_for_any_property?(observer)
39
- property_observer_hash.values.map(&:to_a).sum.include?(observer)
40
- end
41
-
42
- def property_observer_hash
43
- @property_observers ||= Hash.new
44
- end
45
-
46
- def property_observer_list(property_name)
47
- property_observer_hash[property_name.to_sym] = Set.new unless property_observer_hash[property_name.to_sym]
48
- property_observer_hash[property_name.to_sym]
49
- end
50
-
51
- def notify_observers(property_name)
52
- property_observer_list(property_name).each {|observer| observer.call(send(property_name))}
53
- end
54
- #TODO upon updating values, make sure dependent observers are cleared (not added as dependents here)
55
-
56
- def add_property_writer_observers(property_name)
57
- property_writer_name = "#{property_name}="
58
- method(property_writer_name)
59
- ensure_array_object_observer(property_name, send(property_name))
60
- begin
61
- method("__original_#{property_writer_name}")
62
- rescue
63
- # TODO consider alias_method or define_method instead
64
- instance_eval "alias __original_#{property_writer_name} #{property_writer_name}"
65
- instance_eval <<-end_eval, __FILE__, __LINE__
66
- def #{property_writer_name}(value)
67
- old_value = self.#{property_name}
68
- unregister_dependent_observers('#{property_name}', old_value)
69
- self.__original_#{property_writer_name}(value)
70
- notify_observers('#{property_name}')
71
- ensure_array_object_observer('#{property_name}', value, old_value)
72
- end
73
- end_eval
74
- end
75
- rescue => e
76
- # ignore writing if no property writer exists
77
- Glimmer::Config.logger&.debug "No need to observe property writer: #{property_writer_name}\n#{e.message}\n#{e.backtrace.join("\n")}"
78
- end
79
-
80
- def unregister_dependent_observers(property_name, old_value)
81
- # TODO look into optimizing this
82
- return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
83
- property_observer_list(property_name).each do |observer|
84
- observer.unregister_dependents_with_observable(observer.registration_for(self, property_name), old_value)
85
- end
86
- end
87
-
88
- def ensure_array_object_observer(property_name, object, old_object = nil)
89
- return unless object.is_a?(Array)
90
- array_object_observer = array_object_observer_for(property_name)
91
- array_observer_registration = array_object_observer.observe(object)
92
- property_observer_list(property_name).each do |observer|
93
- my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
94
- observer.add_dependent(my_registration => array_observer_registration)
95
- end
96
- array_object_observer_for(property_name).unregister(old_object) if old_object.is_a?(ObservableArray)
97
- end
98
-
99
- def array_object_observer_for(property_name)
100
- @array_object_observers ||= {}
101
- unless @array_object_observers.has_key?(property_name)
102
- @array_object_observers[property_name] = ObservableModel::Notifier.new(self, property_name)
103
- end
104
- @array_object_observers[property_name]
105
- end
106
- end
107
- end
108
- end
@@ -1,124 +0,0 @@
1
- require 'glimmer/error'
2
-
3
- module Glimmer
4
- module DataBinding
5
- # Mixin representing Observer trait from Observer Design Pattern
6
- # Allows classes to include without interfering with their
7
- # inheritance hierarchy.
8
- #
9
- # Includes a default implementation that can receive an observer block
10
- # Example: Observer.proc {|new_value| puts new_value}
11
- # Subclasses may override
12
- module Observer
13
- # Observer Proc default implementation that takes an observer block to process updates
14
- # via call method
15
- class Proc
16
- include Observer
17
-
18
- def initialize(&observer_block)
19
- @observer_block = observer_block
20
- end
21
-
22
- # Called by observables once updates occur sending in the new_value if any
23
- def call(new_value=nil)
24
- @observer_block.call(new_value)
25
- end
26
- end
27
-
28
- class Registration < Struct.new(:observer, :observable, :property, keyword_init: true)
29
- def unregister
30
- observer.unobserve(observable, property)
31
- end
32
- alias unobserve unregister
33
- end
34
-
35
- class << self
36
- def proc(&observer_block)
37
- Proc.new(&observer_block)
38
- end
39
- end
40
-
41
- def registrations
42
- @registrations ||= Set.new
43
- end
44
-
45
- def registration_for(observable, property = nil)
46
- Registration.new(observer: self, observable: observable, property: property)
47
- end
48
-
49
- # mapping of registrations to dependents
50
- # {[observable, property] => [[dependent, dependent_observable, dependent_property], ...]}
51
- def dependents
52
- @dependents ||= Hash.new
53
- end
54
-
55
- def dependents_for(registration)
56
- dependents[registration] ||= Set.new
57
- end
58
-
59
- # registers observer in an observable on a property (optional)
60
- # observer maintains registration list to unregister later
61
- def register(observable, property = nil)
62
- unless observable.is_a?(Observable)
63
- # TODO refactor code to be more smart/polymorphic/automated and honor open/closed principle
64
- if observable.is_a?(Array)
65
- observable.extend(ObservableArray)
66
- else
67
- observable.extend(ObservableModel)
68
- end
69
- end
70
- observable.add_observer(*[self, property].compact)
71
- registration_for(observable, property).tap do |registration|
72
- self.registrations << registration
73
- end
74
- end
75
- alias observe register
76
-
77
- def unregister(observable, property = nil)
78
- # TODO optimize performance in the future via indexing and/or making a registration official object/class
79
- observable.remove_observer(*[self, property].compact)
80
- registration = registration_for(observable, property)
81
- dependents_for(registration).each do |dependent|
82
- dependent.unregister
83
- remove_dependent(registration => dependent)
84
- end
85
- registrations.delete(registration)
86
- end
87
- alias unobserve unregister
88
-
89
- def unregister_dependents_with_observable(registration, dependent_observable)
90
- thedependents = dependents_for(registration).select do |thedependent|
91
- thedependent.observable == dependent_observable
92
- end
93
- thedependents.each do |thedependent|
94
- thedependent.unregister
95
- end
96
- end
97
-
98
- # cleans up all registrations in observables
99
- def unregister_all_observables
100
- registrations.each do |registration|
101
- registration.unregister
102
- end
103
- end
104
- alias unobserve_all_observables unregister_all_observables
105
-
106
- # add dependent observer to unregister when unregistering observer
107
- def add_dependent(parent_to_dependent_hash)
108
- registration = parent_to_dependent_hash.keys.first
109
- dependent = parent_to_dependent_hash.values.first
110
- dependents_for(registration) << dependent
111
- end
112
-
113
- def remove_dependent(parent_to_dependent_hash)
114
- registration = parent_to_dependent_hash.keys.first
115
- dependent = parent_to_dependent_hash.values.first
116
- dependents_for(registration).delete(dependent)
117
- end
118
-
119
- def call(new_value)
120
- raise Error, 'Not implemented!'
121
- end
122
- end
123
- end
124
- end