isomorfeus-data 1.0.0.delta11

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,169 @@
1
+ module LucidHash
2
+ module Mixin
3
+ def self.included(base)
4
+ if RUBY_ENGINE != 'opal'
5
+ Isomorfeus.add_valid_hash_class(base) unless base == LucidHash::Base
6
+ end
7
+
8
+ base.extend(Isomorfeus::Data::PropDeclaration)
9
+
10
+ def to_gid
11
+ [@class_name, @props_json]
12
+ end
13
+
14
+ def to_transport(inline: false)
15
+ if inline
16
+ { '_inline' => { @props_json => to_h }}
17
+ else
18
+ { 'hashes' => { @class_name => { @props_json => to_h }}}
19
+ end
20
+ end
21
+
22
+ base.instance_exec do
23
+ def on_load_block
24
+ @on_load_block
25
+ end
26
+
27
+ def query_block
28
+ @query_block
29
+ end
30
+ end
31
+
32
+ if RUBY_ENGINE == 'opal'
33
+ def initialize(store_path: nil, validated_props: nil)
34
+ @props = validated_props
35
+ @props_json = @props.to_json if @props
36
+ @class_name = self.class.name
37
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
38
+ @store_path = store_path ? store_path : [:data_state, :hashes, @class_name]
39
+ end
40
+
41
+ def loaded?
42
+ Redux.fetch_by_path(*(@store_path + [@props_json])) ? true : false
43
+ end
44
+
45
+ def [](name)
46
+ path = @store_path + [@props_json, name]
47
+ Redux.register_used_store_path(*path)
48
+ result = Redux.fetch_by_path(*path)
49
+ result ? result : nil
50
+ end
51
+
52
+ def key?(name)
53
+ path = @store_path + [@props_json, name]
54
+ Redux.register_used_store_path(*path)
55
+ Redux.fetch_by_path(*path) ? true : false
56
+ end
57
+
58
+ def method_missing(method_name, *args, &block)
59
+ path = @store_path + [@props_json]
60
+ Redux.register_used_store_path(*path)
61
+ raw_hash = Redux.fetch_by_path(*path)
62
+ if raw_hash
63
+ Hash.new(raw_hash).send(method_name, *args, &block)
64
+ else
65
+ Hash.new.send(method_name, *args, &block)
66
+ end
67
+ end
68
+
69
+ def to_h
70
+ raw_hash = Redux.fetch_by_path(*(@store_path + [@props_json]))
71
+ raw_hash ? Hash.new(raw_hash) : {}
72
+ end
73
+
74
+ base.instance_exec do
75
+ def load(props_hash = {})
76
+ validate_props(props_hash)
77
+ instance = self.new(validated_props: Isomorfeus::Data::Props.new(props_hash))
78
+ self.promise_load(props_hash, instance) unless instance.loaded?
79
+ instance
80
+ end
81
+
82
+ def on_load(&block)
83
+ end
84
+
85
+ def promise_load(props_hash = {}, instance = nil)
86
+ unless instance
87
+ validate_props(props_hash)
88
+ instance = self.new(validated_props: Isomorfeus::Data::Props.new(props_hash))
89
+ end
90
+
91
+ props_json = instance.instance_variable_get(:@props_json)
92
+
93
+ Redux.register_used_store_path(:data_state, :hashes, self.name, props_json)
94
+
95
+ Isomorfeus::Transport.promise_send_path('Isomorfeus::Data::Handler::HashLoadHandler', self.name, props_json).then do |response|
96
+ if response[:agent_response].key?(:error)
97
+ `console.error(#{response[:agent_response][:error].to_n})`
98
+ raise response[:agent_response][:error]
99
+ end
100
+ Isomorfeus.store.dispatch(type: 'DATA_LOAD', data: response[:full_response][:data])
101
+ instance
102
+ end
103
+ end
104
+
105
+ def query
106
+ nil
107
+ end
108
+ end
109
+ else # RUBY_ENGINE
110
+ unless base == LucidHash::Base
111
+ base.prop :pub_sub_client, default: nil
112
+ base.prop :session_id, default: nil
113
+ base.prop :current_user, default: nil
114
+ end
115
+
116
+ def initialize(store_path: nil, validated_props: nil)
117
+ @props = validated_props
118
+ @props_json = @props.to_json if @props
119
+ @loaded = false
120
+ @class_name = self.class.name
121
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
122
+ end
123
+
124
+ def loaded?
125
+ @loaded
126
+ end
127
+
128
+ def [](name)
129
+ @data_hash[name]
130
+ end
131
+
132
+ def method_missing(method_name, *args, &block)
133
+ @data_hash.send(method_name, *args, &block)
134
+ end
135
+
136
+ def to_h
137
+ @data_hash.to_h.transform_keys { |k| k.to_s }
138
+ end
139
+
140
+ base.instance_exec do
141
+ def load(props_hash = {})
142
+ validate_props(props_hash)
143
+ instance = self.new(validated_props: Isomorfeus::Data::Props.new(props_hash))
144
+ instance.instance_exec do
145
+ @data_hash = self.class.query_block.call(props_hash)
146
+ @loaded = true
147
+ end
148
+ instance
149
+ end
150
+
151
+ def on_load(&block)
152
+ @on_load_block = block
153
+ end
154
+
155
+ def promise_load(props_hash = {}, instance = nil)
156
+ instance = self.load(props_hash)
157
+ result_promise = Promise.new
158
+ result_promise.resolve(instance)
159
+ result_promise
160
+ end
161
+
162
+ def query(&block)
163
+ @query_block = block
164
+ end
165
+ end
166
+ end # RUBY_ENGINE
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,5 @@
1
+ module LucidNode
2
+ class Base
3
+ include LucidNode::Mixin
4
+ end
5
+ end
@@ -0,0 +1,201 @@
1
+ # api
2
+ # class:
3
+ # attribute :my_attribute, server_only: false|true, class: ClassName, is_a: ClassName, default: value, validate: block
4
+ # my_node.class.attributes
5
+ # my_node.class.attribute_options
6
+ # instance:
7
+ # my_node.my_attribute
8
+ # my_node.my_attribute = value
9
+ # my_node.changed_attributes
10
+ # my_node.changed?
11
+ # my_node.loaded?
12
+ # my_node.valid_attribute?(attr, value)
13
+ # my_node.validate_attribute!(attr, value)
14
+ # my_node.to_transport
15
+
16
+ module LucidNode
17
+ module Mixin
18
+ def self.included(base)
19
+ attr_reader :id
20
+
21
+ def ==(other_node)
22
+ eql?(other_node)
23
+ end
24
+
25
+ def eql?(other_node)
26
+ @id == other_node.id && @class_name == other_node.instance_variable_get(:@class_name)
27
+ end
28
+
29
+ def id=(new_id)
30
+ new_id = new_id.to_s
31
+ changed_attributes[:id] = new_id
32
+ @id = new_id
33
+ end
34
+
35
+ def changed_attributes
36
+ @changed_attributes ||= Isomorfeus::Data::Props.new({})
37
+ end
38
+
39
+ def changed?
40
+ changed_attributes.any?
41
+ end
42
+
43
+ def to_cid
44
+ [@class_name, @id]
45
+ end
46
+
47
+ def valid_attribute?(attr, value)
48
+ begin
49
+ validate_attribute!(attr, value)
50
+ true
51
+ rescue
52
+ false
53
+ end
54
+ end
55
+
56
+ def validate_attribute!(attr, value)
57
+ attr_options = self.class.attribute_options[attr]
58
+
59
+ if attr_options.key?(:class)
60
+ raise "#{attr}: value class is not #{attr_options[:class]}!" unless value.class == attr_options[:class]
61
+ end
62
+
63
+ if attr_options.key?(:is_a)
64
+ raise "#{attr}: value is not a #{attr_options[:class]}!" unless value.is_a?(attr_options[:is_a])
65
+ end
66
+
67
+ if attr_options.key?(:validate)
68
+ raise "#{attr}: value failed validation!" unless attr_options[:validate].call(value)
69
+ end
70
+ end
71
+
72
+ base.instance_exec do
73
+ def query_block
74
+ @query_block
75
+ end
76
+
77
+ def attributes
78
+ attribute_options.keys
79
+ end
80
+
81
+ def attribute_options
82
+ @attribute_options ||= { id: {} }
83
+ end
84
+
85
+ def node_from_cid(cid)
86
+ Isomorfeus.cached_node_class(cid[0]).new({id: cid[1]})
87
+ end
88
+ end
89
+
90
+ if RUBY_ENGINE == 'opal'
91
+ def initialize(attributes_hash = nil)
92
+ attributes_hash = {} unless attributes_hash
93
+ self.class.attributes.each do |attr|
94
+ if attributes_hash.key?(attr)
95
+ validate_attribute!(attr, attributes_hash[attr])
96
+ changed_attributes[attr] = attributes_hash[attr]
97
+ elsif self.class.attribute_options[attr].key?(:default)
98
+ changed_attributes[attr] = self.class.attribute_options[attr][:default]
99
+ end
100
+ end
101
+ @id = attributes_hash[:id].to_s
102
+ @id = "new_#{object_id}" if @id.empty?
103
+ @class_name = self.class.name
104
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
105
+ end
106
+
107
+ def loaded?
108
+ Redux.fetch_by_path(:data_state, :node, @class_name, :instances, @id) ? true : false
109
+ end
110
+
111
+ def to_transport(*args)
112
+ Redux.register_used_store_path(:data_state, :nodes, @class_name, @id)
113
+ final_attributes = {}
114
+ self.class.attributes.each do |attr|
115
+ next if attr == :id
116
+ final_attributes[attr] = send(attr)
117
+ end
118
+ { 'nodes' => { @class_name => { @id => { attributes: final_attributes }}}}
119
+ end
120
+
121
+ base.instance_exec do
122
+ def attribute(name, options = {})
123
+ attribute_options[name] = options
124
+
125
+ define_method(name) do
126
+ Redux.register_used_store_path(:data_state, :nodes, @class_name, @id, :attributes, name)
127
+ if changed_attributes.key?(name)
128
+ changed_attributes[name]
129
+ else
130
+ Redux.fetch_by_path(:data_state, :nodes, @class_name, @id, :attributes, name)
131
+ end
132
+ end
133
+
134
+ define_method("#{name}=") do |arg|
135
+ validate_attribute!(name, arg)
136
+ Redux.register_used_store_path(:data_state, :nodes, @class_name, @id, :attributes, name)
137
+ changed_attributes.set(name, arg)
138
+ end
139
+ end
140
+
141
+ def query
142
+ nil
143
+ end
144
+ end
145
+ else # RUBY_ENGINE
146
+ def initialize(attributes_hash = nil)
147
+ attributes_hash = {} unless attributes_hash
148
+ given_attributes = Isomorfeus::Data::Props.new(attributes_hash)
149
+ valid_attributes_hash = {}
150
+ self.class.attributes.each do |attr|
151
+ if given_attributes.key?(attr)
152
+ validate_attribute!(attr, given_attributes[attr])
153
+ valid_attributes_hash[attr] = given_attributes[attr]
154
+ elsif self.class.attribute_options[attr].key?(:default)
155
+ valid_attributes_hash[attr] = self.class.attribute_options[attr][:default]
156
+ end
157
+ end
158
+ @attributes = Isomorfeus::Data::Props.new(valid_attributes_hash)
159
+ @id = @attributes[:id].to_s
160
+ @id = "new_#{object_id}" if @id.empty?
161
+ @class_name = self.class.name
162
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
163
+ end
164
+
165
+ def loaded?
166
+ true
167
+ end
168
+
169
+ def to_transport(*args)
170
+ final_attributes = {}
171
+ self.class.attributes.each do |attr|
172
+ next if attr == :id
173
+ include_attribute = @attributes.key?(attr)
174
+ include_attribute = !self.class.attribute_options[attr][:server_only] if self.class.attribute_options[attr].key?(:server_only)
175
+ final_attributes[attr.to_s] = send(attr) if include_attribute
176
+ end
177
+ { 'nodes' => { @class_name => { @id => { 'attributes' => final_attributes }}}}
178
+ end
179
+
180
+ base.instance_exec do
181
+ def attribute(name, options = {})
182
+ attribute_options[name] = options
183
+
184
+ define_method(name) do
185
+ if changed_attributes.key?(name)
186
+ changed_attributes[name]
187
+ else
188
+ @attributes[name]
189
+ end
190
+ end
191
+
192
+ define_method("#{name}=") do |arg|
193
+ validate_attribute!(name, arg)
194
+ changed_attributes.set(name, arg)
195
+ end
196
+ end
197
+ end
198
+ end # RUBY_ENGINE
199
+ end
200
+ end
201
+ end
metadata ADDED
@@ -0,0 +1,180 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: isomorfeus-data
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.delta11
5
+ platform: ruby
6
+ authors:
7
+ - Jan Biedermann
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-08-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: oj
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 3.8.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 3.8.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: opal
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.11.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.11.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: opal-activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.3.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.3.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: opal-autoloader
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.1.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.1.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: isomorfeus-react
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 16.9.2
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 16.9.2
97
+ - !ruby/object:Gem::Dependency
98
+ name: isomorfeus-redux
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 4.0.11
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 4.0.11
111
+ - !ruby/object:Gem::Dependency
112
+ name: isomorfeus-transport
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '='
116
+ - !ruby/object:Gem::Version
117
+ version: 1.0.0.delta11
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '='
123
+ - !ruby/object:Gem::Version
124
+ version: 1.0.0.delta11
125
+ description: Write Browser Apps that transparently access server side data with Graphs
126
+ and Collections with ease.
127
+ email: jan@kursator.de
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - LICENSE
133
+ - README.md
134
+ - lib/isomorfeus-data.rb
135
+ - lib/isomorfeus/data/config.rb
136
+ - lib/isomorfeus/data/core_ext/hash/deep_merge.rb
137
+ - lib/isomorfeus/data/handler/array_load_handler.rb
138
+ - lib/isomorfeus/data/handler/collection_load_handler.rb
139
+ - lib/isomorfeus/data/handler/graph_load_handler.rb
140
+ - lib/isomorfeus/data/handler/hash_load_handler.rb
141
+ - lib/isomorfeus/data/prop_declaration.rb
142
+ - lib/isomorfeus/data/props.rb
143
+ - lib/isomorfeus/data/reducer.rb
144
+ - lib/isomorfeus/data/version.rb
145
+ - lib/lucid_array/base.rb
146
+ - lib/lucid_array/mixin.rb
147
+ - lib/lucid_collection/base.rb
148
+ - lib/lucid_collection/mixin.rb
149
+ - lib/lucid_edge/base.rb
150
+ - lib/lucid_edge/mixin.rb
151
+ - lib/lucid_graph/base.rb
152
+ - lib/lucid_graph/mixin.rb
153
+ - lib/lucid_hash/base.rb
154
+ - lib/lucid_hash/mixin.rb
155
+ - lib/lucid_node/base.rb
156
+ - lib/lucid_node/mixin.rb
157
+ homepage: http://isomorfeus.com
158
+ licenses:
159
+ - MIT
160
+ metadata: {}
161
+ post_install_message:
162
+ rdoc_options: []
163
+ require_paths:
164
+ - lib
165
+ required_ruby_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ required_rubygems_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">"
173
+ - !ruby/object:Gem::Version
174
+ version: 1.3.1
175
+ requirements: []
176
+ rubygems_version: 3.0.3
177
+ signing_key:
178
+ specification_version: 4
179
+ summary: Compose Graphs and Collections of data just as needed for a isomorfeus app.
180
+ test_files: []