isomorfeus-data 1.0.0.delta11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c88289965bb31facfa65c47f0765ce3666ceb4037396dfad2cc7f186b26015cc
4
+ data.tar.gz: 4324025cab83a20528a5cc1003111cb6315cb4332998bde4acdedbeea3d18a9a
5
+ SHA512:
6
+ metadata.gz: 37f57249d5a9605b4beb5ff9d84e5959636ccb33f64a643f7c5ba56b7e2b8392f8778a61c949e3fd5f34e25691e58e68f76d1966cf8660a398a511d965d58b74
7
+ data.tar.gz: 3cb3de2349ab663682381cabd57a70f29819efb2ef7760fc0d5bb9ce065a7eb83f1b652ff9fff5f0d5abf1b82b962813520612e58b67675a9366e178e0ebf198
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Jan Biedermann
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # isomorfeus-data
2
+
3
+ see docs for now
@@ -0,0 +1,116 @@
1
+ module Isomorfeus
2
+ # available settings
3
+ class << self
4
+ def cached_array_classes
5
+ @cached_array_classes ||= {}
6
+ end
7
+
8
+ def cached_array_class(class_name)
9
+ return cached_array_classes[class_name] if cached_array_classes.key?(class_name)
10
+ cached_array_classes[class_name] = "::#{class_name}".constantize
11
+ end
12
+
13
+ def cached_collection_classes
14
+ @cached_collection_classes ||= {}
15
+ end
16
+
17
+ def cached_collection_class(class_name)
18
+ return cached_collection_classes[class_name] if cached_collection_classes.key?(class_name)
19
+ cached_collection_classes[class_name] = "::#{class_name}".constantize
20
+ end
21
+
22
+ def cached_edge_classes
23
+ @cached_edge_classes ||= {}
24
+ end
25
+
26
+ def cached_edge_class(class_name)
27
+ return cached_edge_classes[class_name] if cached_edge_classes.key?(class_name)
28
+ cached_edge_classes[class_name] = "::#{class_name}".constantize
29
+ end
30
+
31
+ def cached_graph_classes
32
+ @cached_graph_classes ||= {}
33
+ end
34
+
35
+ def cached_graph_class(class_name)
36
+ return cached_graph_classes[class_name] if cached_graph_classes.key?(class_name)
37
+ cached_graph_classes[class_name] = "::#{class_name}".constantize
38
+ end
39
+
40
+ def cached_hash_classes
41
+ @cached_hash_classes ||= {}
42
+ end
43
+
44
+ def cached_hash_class(class_name)
45
+ return cached_hash_classes[class_name] if cached_hash_classes.key?(class_name)
46
+ cached_hash_classes[class_name] = "::#{class_name}".constantize
47
+ end
48
+
49
+ def cached_node_classes
50
+ @cached_node_classes ||= {}
51
+ end
52
+
53
+ def cached_node_class(class_name)
54
+ return cached_node_classes[class_name] if cached_node_classes.key?(class_name)
55
+ cached_node_classes[class_name] = "::#{class_name}".constantize
56
+ end
57
+
58
+ if RUBY_ENGINE != 'opal'
59
+ def valid_array_class_names
60
+ @valid_array_class_names ||= Set.new
61
+ end
62
+
63
+ def valid_array_class_name?(class_name)
64
+ valid_array_class_names.include?(class_name)
65
+ end
66
+
67
+ def add_valid_array_class(klass)
68
+ class_name = klass.name
69
+ class_name = class_name.split('>::').last if class_name.start_with?('#<')
70
+ valid_array_class_names << class_name
71
+ end
72
+
73
+ def valid_collection_class_names
74
+ @valid_collection_class_names ||= Set.new
75
+ end
76
+
77
+ def valid_collection_class_name?(class_name)
78
+ valid_collection_class_names.include?(class_name)
79
+ end
80
+
81
+ def add_valid_collection_class(klass)
82
+ class_name = klass.name
83
+ class_name = class_name.split('>::').last if class_name.start_with?('#<')
84
+ valid_collection_class_names << class_name
85
+ end
86
+
87
+ def valid_graph_class_names
88
+ @valid_graph_class_names ||= Set.new
89
+ end
90
+
91
+ def valid_graph_class_name?(class_name)
92
+ valid_graph_class_names.include?(class_name)
93
+ end
94
+
95
+ def add_valid_graph_class(klass)
96
+ class_name = klass.name
97
+ class_name = class_name.split('>::').last if class_name.start_with?('#<')
98
+ valid_graph_class_names << class_name
99
+ end
100
+
101
+ def valid_hash_class_names
102
+ @valid_hash_class_names ||= Set.new
103
+ end
104
+
105
+ def valid_hash_class_name?(class_name)
106
+ valid_hash_class_names.include?(class_name)
107
+ end
108
+
109
+ def add_valid_hash_class(klass)
110
+ class_name = klass.name
111
+ class_name = class_name.split('>::').last if class_name.start_with?('#<')
112
+ valid_hash_class_names << class_name
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ # taken from: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
3
+
4
+ class Hash
5
+ # Returns a new hash with +self+ and +other_hash+ merged recursively.
6
+ #
7
+ # h1 = { a: true, b: { c: [1, 2, 3] } }
8
+ # h2 = { a: false, b: { x: [3, 4, 5] } }
9
+ #
10
+ # h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
11
+ #
12
+ # Like with Hash#merge in the standard library, a block can be provided
13
+ # to merge values:
14
+ #
15
+ # h1 = { a: 100, b: 200, c: { c1: 100 } }
16
+ # h2 = { b: 250, c: { c1: 200 } }
17
+ # h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
18
+ # # => { a: 100, b: 450, c: { c1: 300 } }
19
+ def deep_merge(other_hash, &block)
20
+ dup.deep_merge!(other_hash, &block)
21
+ end
22
+
23
+ # Same as +deep_merge+, but modifies +self+.
24
+ def deep_merge!(other_hash, &block)
25
+ merge!(other_hash) do |key, this_val, other_val|
26
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
27
+ this_val.deep_merge(other_val, &block)
28
+ elsif block_given?
29
+ block.call(key, this_val, other_val)
30
+ else
31
+ other_val
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ module Isomorfeus
2
+ module Data
3
+ module Handler
4
+ class ArrayLoadHandler < LucidHandler::Base
5
+ on_request do |pub_sub_client, session_id, current_user, request, response|
6
+ result = { error: 'No such thing' }
7
+ # promise_send_path('Isomorfeus::Data::Handler::CollectionLoadHandler', self.to_s, props_hash)
8
+ request.each_key do |array_class_name|
9
+ if Isomorfeus.valid_array_class_name?(array_class_name)
10
+ array_class = Isomorfeus.cached_array_class(array_class_name)
11
+ if array_class
12
+ props_json = request[array_class_name]
13
+ begin
14
+ props = Oj.load(props_json, mode: :strict)
15
+ props.merge!({pub_sub_client: pub_sub_client, session_id: session_id, current_user: current_user})
16
+ array = array_class.load(props)
17
+ array.instance_exec do
18
+ array_class.on_load_block.call(pub_sub_client, session_id, current_user) if array_class.on_load_block
19
+ end
20
+ response.deep_merge!(data: array.to_transport)
21
+ result = { success: 'ok' }
22
+ rescue Exception => e
23
+ result = if Isomorfeus.production?
24
+ { error: { array_class_name => 'No such thing!' }}
25
+ else
26
+ { error: { array_class_name => "Isomorfeus::Data::Handler::ArrayLoadHandler: #{e.message}" }}
27
+ end
28
+ end
29
+ else
30
+ result = { error: { array_class_name => 'No such thing!' }}
31
+ end
32
+ else
33
+ result = { error: { array_class_name => 'No such thing!' }}
34
+ end
35
+ end
36
+ result
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ module Isomorfeus
2
+ module Data
3
+ module Handler
4
+ class CollectionLoadHandler < LucidHandler::Base
5
+ on_request do |pub_sub_client, session_id, current_user, request, response|
6
+ result = { error: 'No such thing' }
7
+ # promise_send_path('Isomorfeus::Data::Handler::CollectionLoadHandler', self.to_s, props_hash)
8
+ request.each_key do |collection_class_name|
9
+ if Isomorfeus.valid_collection_class_name?(collection_class_name)
10
+ collection_class = Isomorfeus.cached_collection_class(collection_class_name)
11
+ if collection_class
12
+ props_json = request[collection_class_name]
13
+ begin
14
+ props = Oj.load(props_json, mode: :strict)
15
+ props.merge!({pub_sub_client: pub_sub_client, session_id: session_id, current_user: current_user})
16
+ collection = collection_class.load(props)
17
+ collection.instance_exec do
18
+ collection_class.on_load_block.call(pub_sub_client, session_id, current_user) if collection_class.on_load_block
19
+ end
20
+ response.deep_merge!(data: collection.to_transport)
21
+ response.deep_merge!(data: collection.included_items_to_transport)
22
+ result = { success: 'ok' }
23
+ rescue Exception => e
24
+ result = if Isomorfeus.production?
25
+ { error: { collection_class_name => 'No such thing!' }}
26
+ else
27
+ { error: { collection_class_name => "Isomorfeus::Data::Handler::CollectionLoadHandler: #{e.message}" }}
28
+ end
29
+ end
30
+ else
31
+ result = { error: { collection_class_name => 'No such thing!' }}
32
+ end
33
+ else
34
+ result = { error: { collection_class_name => 'No such thing!' }}
35
+ end
36
+ end
37
+ result
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ module Isomorfeus
2
+ module Data
3
+ module Handler
4
+ class GraphLoadHandler < LucidHandler::Base
5
+ on_request do |pub_sub_client, session_id, current_user, request, response|
6
+ result = { error: 'No such thing' }
7
+ # promise_send_path('Isomorfeus::Data::Handler::GraphLoadHandler', self.to_s, props_hash)
8
+ request.each_key do |graph_class_name|
9
+ if Isomorfeus.valid_graph_class_name?(graph_class_name)
10
+ graph_class = Isomorfeus.cached_graph_class(graph_class_name)
11
+ if graph_class
12
+ props_json = request[graph_class_name]
13
+ begin
14
+ props = Oj.load(props_json, mode: :strict)
15
+ props.merge!({pub_sub_client: pub_sub_client, session_id: session_id, current_user: current_user})
16
+ graph = graph_class.load(props)
17
+ graph.instance_exec do
18
+ graph_class.on_load_block.call(pub_sub_client, session_id, current_user) if graph_class.on_load_block
19
+ end
20
+ response.deep_merge!(data: graph.to_transport)
21
+ response.deep_merge!(data: graph.included_items_to_transport)
22
+ result = { success: 'ok' }
23
+ rescue Exception => e
24
+ result = if Isomorfeus.production?
25
+ { error: { graph_class_name => 'No such thing!' }}
26
+ else
27
+ { error: { graph_class_name => "Isomorfeus::Data::Handler::GraphLoadHandler: #{e.message}" }}
28
+ end
29
+ end
30
+ else
31
+ result = { error: { graph_class_name => 'No such thing!' }}
32
+ end
33
+ else
34
+ result = { error: { graph_class_name => 'No such thing!' }}
35
+ end
36
+ end
37
+ result
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ module Isomorfeus
2
+ module Data
3
+ module Handler
4
+ class HashLoadHandler < LucidHandler::Base
5
+ on_request do |pub_sub_client, session_id, current_user, request, response|
6
+ result = { error: 'No such thing' }
7
+ # promise_send_path('Isomorfeus::Data::Handler::HashLoadHandler', self.to_s, props_hash)
8
+ request.each_key do |hash_class_name|
9
+ if Isomorfeus.valid_hash_class_name?(hash_class_name)
10
+ hash_class = Isomorfeus.cached_hash_class(hash_class_name)
11
+ if hash_class
12
+ props_json = request[hash_class_name]
13
+ begin
14
+ props = Oj.load(props_json, mode: :strict)
15
+ props.merge!({pub_sub_client: pub_sub_client, session_id: session_id, current_user: current_user})
16
+ hash = hash_class.load(props)
17
+ hash.instance_exec do
18
+ hash_class.on_load_block.call(pub_sub_client, session_id, current_user) if hash_class.on_load_block
19
+ end
20
+ response.deep_merge!(data: hash.to_transport)
21
+ result = { success: 'ok' }
22
+ rescue Exception => e
23
+ result = if Isomorfeus.production?
24
+ { error: { hash_class_name => 'No such thing!' }}
25
+ else
26
+ { error: { hash_class_name => "Isomorfeus::Data::Handler::HashLoadHandler: #{e.message}" }}
27
+ end
28
+ end
29
+ else
30
+ result = { error: { hash_class_name => 'No such thing!' }}
31
+ end
32
+ else
33
+ result = { error: { hash_class_name => 'No such thing!' }}
34
+ end
35
+ end
36
+ result
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,58 @@
1
+ module Isomorfeus
2
+ module Data
3
+ module PropDeclaration
4
+ # props, very similar to Components:
5
+ # prop :text, class: String # a required prop of class String, class must match exactly
6
+ # prop :other, is_a: Enumerable # a required prop, which can be a Array for example, but at least must be a Enumerable
7
+ # prop :cool, default: 'yet some more text' # a optional prop with a default value
8
+ # prop :even_cooler, class: String, required: false
9
+ def prop(prop_name, options_hash = {})
10
+ declared_props[prop_name.to_sym] = options_hash
11
+ end
12
+
13
+ def declared_props
14
+ @declared_props ||= {}
15
+ end
16
+
17
+ def validate_props(props_hash)
18
+ p = declared_props
19
+
20
+ props = Isomorfeus::Data::Props.new(props_hash)
21
+
22
+ raise "#{self}: Wrong or to many props given!" if (props.keys - p.keys).size > 0
23
+
24
+ # validation
25
+ p.each_key do |key|
26
+ # determine if prop is required
27
+ required = if p[key].key?(:required)
28
+ p[key][:required]
29
+ elsif p[key].key?(:default)
30
+ false
31
+ else
32
+ true
33
+ end
34
+
35
+ # assign value
36
+ value = if props.key?(key)
37
+ props[key]
38
+ elsif p[key].key?(:default)
39
+ props_hash[key] = p[key][:default].dup
40
+ else
41
+ raise "#{self}: Required prop not given: #{key}!" if required
42
+ nil
43
+ end
44
+
45
+ # check if passed value is of correct type
46
+ if props_hash.key?(key)
47
+ if p[key].key?(:class) && value.class != (p[key][:class])
48
+ raise "#{self}: #{key} value is not of class #{p[key][:class]} but instead a #{value.class}!"
49
+ end
50
+ if p[key].key?(:is_a) && !value.is_a?(p[key][:is_a])
51
+ raise "#{self}: #{key} value is not a #{p[key][:is_a]}!"
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,96 @@
1
+ module Isomorfeus
2
+ module Data
3
+ class Props
4
+ def initialize(props_hash)
5
+ props_hash = {} unless props_hash
6
+ @props_hash = props_hash
7
+ end
8
+
9
+ def any?
10
+ @props_hash.keys.size > 0
11
+ end
12
+
13
+ if RUBY_ENGINE == 'opal'
14
+ def [](prop_name)
15
+ @props_hash[prop_name]
16
+ end
17
+
18
+ def []=(prop_name, value)
19
+ @props_hash[prop_name] = value
20
+ end
21
+
22
+ def key?(prop_name)
23
+ @props_hash.key?(prop_name)
24
+ end
25
+
26
+ def keys
27
+ @props_hash.keys
28
+ end
29
+
30
+ def method_missing(prop_name, *args, &block)
31
+ return @props_hash[prop_name] if @props_hash.key?(prop_name)
32
+ super(prop_name, *args, &block)
33
+ end
34
+
35
+ def set(prop_name, value)
36
+ @props_hash[prop_name] = value
37
+ end
38
+
39
+ def to_json
40
+ JSON.dump(to_transport)
41
+ end
42
+
43
+ def to_transport
44
+ transport_hash = {}.merge(@props_hash)
45
+ transport_hash
46
+ end
47
+ else # RUBY_ENGINE
48
+ def [](prop_name)
49
+ name = prop_name.to_sym
50
+ return @props_hash[name] if @props_hash.key?(name)
51
+ name = prop_name.to_s
52
+ return @props_hash[name] if @props_hash.key?(name)
53
+ nil
54
+ end
55
+
56
+ def []=(prop_name, value)
57
+ @props_hash[prop_name.to_sym] = value
58
+ end
59
+
60
+ def key?(prop_name)
61
+ @props_hash.key?(prop_name.to_sym) || @props_hash.key?(prop_name.to_s)
62
+ end
63
+
64
+ def keys
65
+ @props_hash.keys.map(&:to_sym)
66
+ end
67
+
68
+ def method_missing(prop_name, *args, &block)
69
+ name = prop_name.to_sym
70
+ return @props_hash[name] if @props_hash.key?(name)
71
+ name = prop_name.to_s
72
+ return @props_hash[name] if @props_hash.key?(name)
73
+ super(prop_name, *args, &block)
74
+ end
75
+
76
+ def set(prop_name, value)
77
+ @props_hash[prop_name.to_sym] = value
78
+ end
79
+
80
+ def to_json
81
+ Oj.dump(to_transport, mode: :strict)
82
+ end
83
+
84
+ def to_transport
85
+ transport_hash = {}.merge(@props_hash)
86
+ transport_hash.delete(:pub_sub_client)
87
+ transport_hash.delete(:session_id)
88
+ transport_hash.delete(:current_user)
89
+ transport_hash
90
+ end
91
+ end # RUBY_ENGINE
92
+
93
+ alias_method :has_key?, :key?
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,30 @@
1
+ module Isomorfeus
2
+ module Data
3
+ module Reducer
4
+ def self.add_reducer_to_store
5
+ data_reducer = Redux.create_reducer do |prev_state, action|
6
+ action_type = action[:type]
7
+ if action_type.JS.startsWith('DATA_')
8
+ case action_type
9
+ when 'DATA_STATE'
10
+ if action.key?(:set_state)
11
+ action[:set_state]
12
+ else
13
+ prev_state
14
+ end
15
+ when 'DATA_LOAD'
16
+ prev_state.deep_merge(action[:data])
17
+ else
18
+ prev_state
19
+ end
20
+ else
21
+ prev_state
22
+ end
23
+ end
24
+
25
+ Redux::Store.preloaded_state_merge!(data_state: {})
26
+ Redux::Store.add_reducer(data_state: data_reducer)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ module Isomorfeus
2
+ module Data
3
+ VERSION = '1.0.0.delta11'
4
+ end
5
+ end
@@ -0,0 +1,48 @@
1
+ require 'opal'
2
+ require 'opal-autoloader'
3
+ require 'opal-activesupport'
4
+ require 'isomorfeus-redux'
5
+ require 'isomorfeus-transport'
6
+
7
+ require 'isomorfeus/data/config'
8
+ require 'isomorfeus/data/props'
9
+ require 'isomorfeus/data/prop_declaration'
10
+ require 'lucid_node/mixin'
11
+ require 'lucid_node/base'
12
+ require 'lucid_edge/mixin'
13
+ require 'lucid_edge/base'
14
+ require 'lucid_array/mixin'
15
+ require 'lucid_array/base'
16
+ require 'lucid_collection/mixin'
17
+ require 'lucid_collection/base'
18
+ require 'lucid_graph/mixin'
19
+ require 'lucid_graph/base'
20
+ require 'lucid_hash/mixin'
21
+ require 'lucid_hash/base'
22
+
23
+ if RUBY_ENGINE == 'opal'
24
+ require 'isomorfeus/data/core_ext/hash/deep_merge'
25
+ require 'isomorfeus/data/reducer'
26
+ Isomorfeus::Data::Reducer.add_reducer_to_store
27
+ Opal::Autoloader.add_load_path('data')
28
+ else
29
+ require 'oj'
30
+ require 'active_support'
31
+ require 'active_support/core_ext/hash'
32
+ require 'isomorfeus/data/handler/array_load_handler'
33
+ require 'isomorfeus/data/handler/collection_load_handler'
34
+ require 'isomorfeus/data/handler/graph_load_handler'
35
+ require 'isomorfeus/data/handler/hash_load_handler'
36
+
37
+ Opal.append_path(__dir__.untaint) unless Opal.paths.include?(__dir__.untaint)
38
+
39
+ require 'active_support/dependencies'
40
+
41
+ path = File.expand_path(File.join('isomorfeus', 'data'))
42
+
43
+ ActiveSupport::Dependencies.autoload_paths << path
44
+ # we also need to require them all, so classes are registered accordingly
45
+ Dir.glob("#{path}/**/*.rb").each do |file|
46
+ require file
47
+ end
48
+ end
@@ -0,0 +1,15 @@
1
+ module LucidArray
2
+ class Base
3
+ include LucidArray::Mixin
4
+
5
+ if RUBY_ENGINE != 'opal'
6
+ def self.inherited(base)
7
+ Isomorfeus.add_valid_array_class(base)
8
+
9
+ base.prop :pub_sub_client, default: nil
10
+ base.prop :session_id, default: nil
11
+ base.prop :current_user, default: nil
12
+ end
13
+ end
14
+ end
15
+ end