kantox-split 0.2.0

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
+ SHA1:
3
+ metadata.gz: 3cb0f60879f9ec28ba4c9126ffc4be86b89086b9
4
+ data.tar.gz: b777254cd8242e5fc749e8af907e92fd7c347aea
5
+ SHA512:
6
+ metadata.gz: 5054b81ed6166717e681c78bcbd78dbe0eb51b663802481ab95340aa0c4e4f765aaa262d572b686c5ef98d3d547a6af4a4a8b12b7496206e1399c1a4c027099c
7
+ data.tar.gz: 3084b9bc907bb1ce883d7c2c4a1c8c305898b45395fe486963ff0f7b487bd25b37c067d8043bf08d7d0d46360943cf69788aea23ac0a5fc6680977e80b68d8da
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1 @@
1
+ inherit_from: .rubocop_todo.yml
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,243 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-05-12 15:22:43 +0200 using RuboCop version 0.39.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: AllowSafeAssignment.
11
+ Lint/AssignmentInCondition:
12
+ Exclude:
13
+ - 'lib/kantox/split/adapters/getters.rb'
14
+
15
+ # Offense count: 4
16
+ # Cop supports --auto-correct.
17
+ Lint/Debugger:
18
+ Exclude:
19
+ - 'lib/kantox/split/adapters/file_io.rb'
20
+ - 'lib/kantox/split/adapters/rethink-db.rb'
21
+
22
+ # Offense count: 1
23
+ # Cop supports --auto-correct.
24
+ # Configuration parameters: IgnoreEmptyBlocks.
25
+ Lint/UnusedBlockArgument:
26
+ Exclude:
27
+ - 'lib/kantox/split/graph.rb'
28
+
29
+ # Offense count: 1
30
+ # Cop supports --auto-correct.
31
+ # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
32
+ Lint/UnusedMethodArgument:
33
+ Exclude:
34
+ - 'lib/kantox/split/graph.rb'
35
+
36
+ # Offense count: 5
37
+ Metrics/AbcSize:
38
+ Max: 33
39
+
40
+ # Offense count: 5
41
+ Metrics/CyclomaticComplexity:
42
+ Max: 9
43
+
44
+ # Offense count: 28
45
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
46
+ # URISchemes: http, https
47
+ Metrics/LineLength:
48
+ Max: 161
49
+
50
+ # Offense count: 1
51
+ # Configuration parameters: CountComments.
52
+ Metrics/MethodLength:
53
+ Max: 34
54
+
55
+ # Offense count: 2
56
+ Metrics/PerceivedComplexity:
57
+ Max: 9
58
+
59
+ # Offense count: 1
60
+ Style/AsciiComments:
61
+ Exclude:
62
+ - 'lib/kantox/split/adapters/getters.rb'
63
+
64
+ # Offense count: 4
65
+ Style/CaseEquality:
66
+ Exclude:
67
+ - 'lib/kantox/split/adapters/file_io.rb'
68
+ - 'lib/kantox/split/adapters/rethink-db.rb'
69
+
70
+ # Offense count: 2
71
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
72
+ # SupportedStyles: nested, compact
73
+ Style/ClassAndModuleChildren:
74
+ Exclude:
75
+ - 'lib/kantox/split.rb'
76
+
77
+ # Offense count: 2
78
+ # Cop supports --auto-correct.
79
+ # Configuration parameters: Keywords.
80
+ # Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW
81
+ Style/CommentAnnotation:
82
+ Exclude:
83
+ - 'lib/kantox/split/graph.rb'
84
+
85
+ # Offense count: 1
86
+ # Cop supports --auto-correct.
87
+ Style/CommentIndentation:
88
+ Exclude:
89
+ - 'kantox-split.gemspec'
90
+
91
+ # Offense count: 16
92
+ Style/Documentation:
93
+ Exclude:
94
+ - 'spec/**/*'
95
+ - 'test/**/*'
96
+ - 'lib/kantox/split.rb'
97
+ - 'lib/kantox/split/adapters/file_io.rb'
98
+ - 'lib/kantox/split/adapters/getters.rb'
99
+ - 'lib/kantox/split/adapters/rethink-db.rb'
100
+ - 'lib/kantox/split/graph.rb'
101
+ - 'lib/kantox/split/hooker.rb'
102
+ - 'lib/kantox/split/utils.rb'
103
+
104
+ # Offense count: 1
105
+ Style/EachWithObject:
106
+ Exclude:
107
+ - 'lib/kantox/split/graph.rb'
108
+
109
+ # Offense count: 8
110
+ # Cop supports --auto-correct.
111
+ # Configuration parameters: AllowAdjacentOneLineDefs.
112
+ Style/EmptyLineBetweenDefs:
113
+ Exclude:
114
+ - 'lib/kantox/split.rb'
115
+ - 'lib/kantox/split/adapters/file_io.rb'
116
+ - 'lib/kantox/split/adapters/rethink-db.rb'
117
+ - 'lib/kantox/split/utils.rb'
118
+
119
+ # Offense count: 1
120
+ # Cop supports --auto-correct.
121
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
122
+ # SupportedStyles: empty_lines, no_empty_lines
123
+ Style/EmptyLinesAroundBlockBody:
124
+ Exclude:
125
+ - 'kantox-split.gemspec'
126
+
127
+ # Offense count: 1
128
+ # Cop supports --auto-correct.
129
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
130
+ # SupportedStyles: empty_lines, no_empty_lines
131
+ Style/EmptyLinesAroundModuleBody:
132
+ Exclude:
133
+ - 'lib/kantox/split/adapters/getters.rb'
134
+
135
+ # Offense count: 1
136
+ # Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts.
137
+ Style/FileName:
138
+ Exclude:
139
+ - 'lib/kantox/split/adapters/rethink-db.rb'
140
+
141
+ # Offense count: 25
142
+ # Cop supports --auto-correct.
143
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
144
+ # SupportedStyles: require_parentheses, require_no_parentheses, require_no_parentheses_except_multiline
145
+ Style/MethodDefParentheses:
146
+ Enabled: false
147
+
148
+ # Offense count: 2
149
+ # Cop supports --auto-correct.
150
+ # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
151
+ # SupportedStyles: aligned, indented
152
+ Style/MultilineMethodCallIndentation:
153
+ Enabled: false
154
+
155
+ # Offense count: 3
156
+ Style/MultilineTernaryOperator:
157
+ Exclude:
158
+ - 'lib/kantox/split/adapters/getters.rb'
159
+ - 'lib/kantox/split/utils.rb'
160
+
161
+ # Offense count: 3
162
+ # Cop supports --auto-correct.
163
+ Style/MutableConstant:
164
+ Exclude:
165
+ - 'lib/kantox/split/graph.rb'
166
+ - 'lib/kantox/split/hooker.rb'
167
+ - 'lib/kantox/split/version.rb'
168
+
169
+ # Offense count: 1
170
+ Style/NestedTernaryOperator:
171
+ Exclude:
172
+ - 'lib/kantox/split/adapters/getters.rb'
173
+
174
+ # Offense count: 1
175
+ # Cop supports --auto-correct.
176
+ Style/NumericLiterals:
177
+ MinDigits: 6
178
+
179
+ # Offense count: 3
180
+ # Configuration parameters: SupportedStyles.
181
+ # SupportedStyles: compact, exploded
182
+ Style/RaiseArgs:
183
+ EnforcedStyle: compact
184
+
185
+ # Offense count: 1
186
+ # Cop supports --auto-correct.
187
+ Style/RedundantSelf:
188
+ Exclude:
189
+ - 'lib/kantox/split/graph.rb'
190
+
191
+ # Offense count: 2
192
+ # Cop supports --auto-correct.
193
+ # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
194
+ # SupportedStyles: slashes, percent_r, mixed
195
+ Style/RegexpLiteral:
196
+ Exclude:
197
+ - 'kantox-split.gemspec'
198
+
199
+ # Offense count: 6
200
+ # Cop supports --auto-correct.
201
+ Style/RescueModifier:
202
+ Exclude:
203
+ - 'lib/kantox/split.rb'
204
+ - 'lib/kantox/split/graph.rb'
205
+ - 'lib/kantox/split/utils.rb'
206
+
207
+ # Offense count: 2
208
+ # Cop supports --auto-correct.
209
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
210
+ # SupportedStyles: only_raise, only_fail, semantic
211
+ Style/SignalException:
212
+ Exclude:
213
+ - 'lib/kantox/split/adapters/getters.rb'
214
+ - 'lib/kantox/split/hooker.rb'
215
+
216
+ # Offense count: 2
217
+ # Cop supports --auto-correct.
218
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
219
+ # SupportedStyles: space, no_space
220
+ Style/SpaceBeforeBlockBraces:
221
+ Enabled: false
222
+
223
+ # Offense count: 5
224
+ # Cop supports --auto-correct.
225
+ Style/SpaceInsideBrackets:
226
+ Exclude:
227
+ - 'lib/kantox/split.rb'
228
+ - 'lib/kantox/split/adapters/getters.rb'
229
+ - 'lib/kantox/split/graph.rb'
230
+
231
+ # Offense count: 4
232
+ # Cop supports --auto-correct.
233
+ # Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline.
234
+ # SupportedStyles: single_quotes, double_quotes
235
+ Style/StringLiterals:
236
+ Enabled: false
237
+
238
+ # Offense count: 2
239
+ # Cop supports --auto-correct.
240
+ Style/WhileUntilDo:
241
+ Exclude:
242
+ - 'lib/kantox/split.rb'
243
+ - 'lib/kantox/split/utils.rb'
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kantox-split.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Kantox::Split
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/kantox/split`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'kantox-split'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install kantox-split
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it ( https://github.com/[my-github-username]/kantox-split/fork )
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+
4
+ require 'bundler'
5
+ require 'bundler/setup'
6
+ require 'bundler/gem_tasks'
7
+
8
+ require 'rspec/core/rake_task'
9
+
10
+ begin
11
+ Bundler.setup(:default, :development, :test)
12
+ rescue Bundler::BundlerError => e
13
+ $stderr.puts e.message
14
+ $stderr.puts 'Run `bundle install` to install missing gems'
15
+ exit e.status_code
16
+ end
17
+
18
+ desc 'Tests'
19
+ RSpec::Core::RakeTask.new(:spec) do |spec|
20
+ spec.rspec_opts = '-Ispec'
21
+ # spec.rcov = true
22
+ end
23
+
24
+ require 'cucumber/rake/task'
25
+ desc 'Cucumber'
26
+ Cucumber::Rake::Task.new(:features)
27
+
28
+ task default: [:features, :spec]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "kantox/split"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kantox/split/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'kantox-split'
8
+ spec.version = Kantox::Split::VERSION
9
+ spec.authors = ['Kantox LTD']
10
+ spec.email = ['aleksei.matiushkin@kantox.com']
11
+
12
+ spec.summary = 'Easy split ActiveRecord’s CUD operations to write to separate data source.'
13
+ spec.description = 'This gem is extremely useful while in process of migration to another data source.'
14
+ spec.homepage = 'http://kantox.com'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(/^(test|spec|features)\//) }
17
+ spec.bindir = 'bin'
18
+ spec.executables = spec.files.grep(/^exe\//) { |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ if spec.respond_to?(:metadata)
22
+ # spec.metadata['allowed_push_host'] = "TODO: FURY"
23
+ end
24
+
25
+ spec.add_dependency 'rgl', '~> 0.5'
26
+ spec.add_dependency 'kungfuig', '~> 0'
27
+
28
+ spec.add_development_dependency 'bundler', '~> 1.7'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+
31
+ spec.add_development_dependency 'rspec', '~> 2.12'
32
+ spec.add_development_dependency 'cucumber', '~> 1.3'
33
+ spec.add_development_dependency 'yard', '~> 0'
34
+
35
+ end
@@ -0,0 +1,64 @@
1
+ require 'kantox/split/version'
2
+ require 'kantox/split/hooker'
3
+ require 'kantox/split/adapters'
4
+ require 'kantox/split/graph'
5
+
6
+ module Kantox
7
+ module Split
8
+ class ::ActiveRecord::Base
9
+ include Hooker
10
+ include Adapters::Getters
11
+
12
+ ##########################################################################
13
+ #### Graph for instances
14
+ ##########################################################################
15
+ include Graph::Vertex
16
+ configure_edges do |e|
17
+ e.reflections.values
18
+ end
19
+ configure_embedded :attributes
20
+ configure_schild %w(name caption label)
21
+ .flat_map { |e| [ e, "#{self.class.name.singularize.underscore}_#{e}"] }
22
+ .map { |field| "respond_to?(:#{field}) && #{field}" }.join(' || ') + " || ''"
23
+
24
+ ##########################################################################
25
+ #### Graph for classes
26
+ ##########################################################################
27
+ class << self
28
+ include Graph::Vertex
29
+ configure_edges do |e|
30
+ e.reflections.values
31
+ end
32
+ configure_schild :name
33
+
34
+ def vertices
35
+ edges.map do |edge|
36
+ next [edge.name, ::ActiveRecord::Base] if edge.options[:polymorphic]
37
+
38
+ while edge && edge.options[:through] do
39
+ edge = edges.detect { |e| e.name == edge.options[:through] }
40
+ end
41
+
42
+ edge_singular = (edge.options[:class_name] || edge.name.to_s).singularize.camelize
43
+ edge_singular += 's' if edge_singular[-2..-1] == 'es' # WTF, Rails?
44
+ vtx = edge_singular.constantize rescue edge_singular
45
+ edge && [edge.name, edge.macro == :has_many ? [vtx] : vtx]
46
+ end.compact.to_h
47
+ end
48
+ def to_h levels = 0, collected = []
49
+ { self: attribute_names.map(&:to_sym) }.merge(vertices.map do |k, v|
50
+ v_deep = Kantox::Split::Utils.omnivorous_to_h v, levels, collected
51
+ [k, v == v_deep ? v : { v => v_deep }]
52
+ end.to_h)
53
+ end
54
+ end
55
+ end
56
+
57
+ class ::ActiveRecord::Reflection::MacroReflection
58
+ include Graph::Edge
59
+ configure_vertex do |o|
60
+ { macro: o.macro, name: o.name, method: o.name, options: o.options, class: o.class }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,2 @@
1
+ require 'kantox/split/adapters/getters'
2
+ require 'kantox/split/adapters/rethink-db'
@@ -0,0 +1,58 @@
1
+ module Kantox
2
+ module Split
3
+ module Adapters
4
+ module Getters
5
+ def self.included base
6
+ fail TypeError.new("Hooker may be included in «ActiveRecord::Base»d classes since it requires «after_commit» hook") unless base <= ::ActiveRecord::Base
7
+ [:has_many, :has_one, :composed_of, :belongs_to].each do |r|
8
+ define_method "reflections_#{r}" do
9
+ reflections.group_by{ |_, v| v.macro }[r]
10
+ end
11
+ end
12
+ end
13
+
14
+ # According to `:for_relation`, we’ll follow the relations:
15
+ # :has_many :has_many
16
+ # :belongs_to :belongs_to
17
+ # :has_one none
18
+ def as_document for_reflection = [:has_many, :has_one, :belongs_to], deep = true, collected = []
19
+ this = self
20
+ refls = reflections.group_by{ |_, v| v.macro }
21
+ puts "====> REFLS: #{refls.keys}"
22
+ { attributes: attributes }.merge(deep ?
23
+ [*for_reflection].map do |r|
24
+ next unless refls[r].is_a? Enumerable
25
+ [
26
+ r,
27
+ refls[r].map do |rr|
28
+ begin
29
+ value = this.public_send(rr.first)
30
+ collected << value unless already_collected = collected.include?(value)
31
+ deepers = {
32
+ has_many: [:has_one, :has_many],
33
+ has_one: [:has_one],
34
+ belongs_to: [:belongs_to]
35
+ }
36
+ [
37
+ rr.first,
38
+ already_collected || value.nil? ? value :
39
+ case r
40
+ when :has_many then value.map { |v| v.as_document(deepers[r] & for_reflection, deep, collected) }
41
+ when :has_one, :belongs_to then value.as_document(deepers[r] & for_reflection, deep, collected)
42
+ else value
43
+ end
44
+ ]
45
+ rescue StandardError => e
46
+ puts "CatchedError :: #{e} :: #{r} :: #{rr}"
47
+ [ rr.first, "[ERR] :: #{e.message}" ]
48
+ end
49
+ end.to_h
50
+ ]
51
+ end.compact.to_h
52
+ : {})
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,131 @@
1
+ require 'kantox/split/utils'
2
+ require 'rgl/adjacency'
3
+
4
+ module Kantox
5
+ module Split
6
+ module Graph
7
+ CONFIGURE_EVALUATOR = <<-EOCFGEV
8
+ def configure_%{entity} parameter = nil, &cb
9
+ store_variable :graph_%{entity}_getter, parameter || cb
10
+ class_eval do
11
+ def %{entity}
12
+ lookup_variable_value lookup_variable :graph_%{entity}_getter
13
+ end
14
+ end
15
+ end
16
+ EOCFGEV
17
+
18
+ ##########################################################################
19
+ module Attributed
20
+ include Kantox::Split::Utils
21
+ module ClassMethods
22
+ def configure_embedded parameter = nil, &cb
23
+ store_variable :embedded_parameter_getter, parameter || cb
24
+ class_eval do
25
+ def embedded
26
+ lookup_variable_value lookup_variable :embedded_parameter_getter
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ ##########################################################################
33
+ module Vertex
34
+ def self.included base
35
+ base.include Kantox::Split::Utils
36
+ base.extend Attributed::ClassMethods
37
+ base.include InstanceMethods
38
+ base.extend ClassMethods
39
+ end
40
+
41
+ module InstanceMethods
42
+ def leaf?
43
+ edges.empty?
44
+ end
45
+
46
+ def vertices
47
+ return [] unless respond_to? :edges
48
+ edges.map do |edge|
49
+ edge.vertex_getter.call self rescue nil
50
+ end.compact
51
+ end
52
+
53
+ def graph_node_id
54
+ label = schild if respond_to?(:schild)
55
+ label = label.empty? ? self.class.name : "\"#{label}\": #{self.class.name}"
56
+ "#{label} «#{id rescue nil}»"
57
+ end
58
+
59
+ def to_h levels = 0, collected = []
60
+ (respond_to?(:embedded) && embedded || {}).merge(
61
+ vertices.map do |k, v|
62
+ next if v.nil? || v.respond_to?(:empty?) && v.empty?
63
+ [k[:name], Kantox::Split::Utils.omnivorous_to_h(v, levels, collected, 'obj.respond_to?(:graph_node_id) ? obj.graph_node_id : obj.__id__')]
64
+ end.compact.to_h
65
+ )
66
+ end
67
+
68
+ def to_graph levels = 0, g = RGL::DirectedAdjacencyGraph.new, root = self.graph_node_id
69
+ vertices.each do |k, v|
70
+ next if v.nil? || v.respond_to?(:empty?) && v.empty?
71
+ next unless v.is_a? Vertex # FIXME ARRAY
72
+ g.add_edge(root, vtx = v.graph_node_id)
73
+ v.to_graph(levels - 1, g, vtx) if levels > 0 && v.respond_to?(:to_graph)
74
+ end
75
+ g
76
+ end
77
+ end
78
+
79
+ module ClassMethods
80
+ # to be called as:
81
+ #
82
+ # class ActiveRecord::Base
83
+ # include Kantox::Split::Graph::Vertex
84
+ # configure_edges :reflections # the parameter must be Enumerable
85
+ # ...
86
+ #
87
+ %i(edges schild).each do |entity|
88
+ module_eval CONFIGURE_EVALUATOR % { entity: entity }
89
+ end
90
+ end
91
+ end
92
+ ##########################################################################
93
+ module Edge
94
+ def self.included base
95
+ base.include Kantox::Split::Utils
96
+ base.extend Attributed::ClassMethods
97
+ base.include InstanceMethods
98
+ base.extend ClassMethods
99
+ end
100
+
101
+ module InstanceMethods
102
+ def vertex_getter
103
+ return nil unless respond_to? :vertex
104
+ v = (vtx = vertex).is_a?(Hash) ? vtx[:method] || vtx[:lambda] : vtx
105
+ lambda do |vertex|
106
+ unless [:todos].include? v # FIXME UGLY HACK
107
+ [ vtx, Utils.lookup_variable_value(vertex, v) ]
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ module ClassMethods
114
+ %i(vertex).each do |entity|
115
+ module_eval CONFIGURE_EVALUATOR % { entity: entity }
116
+ end
117
+ end
118
+ end
119
+ ##########################################################################
120
+ def self.tree root, depth = -1
121
+ return nil unless root.respond_to? :vertices
122
+
123
+ root.vertices.inject({}) do |memo, v|
124
+ memo[v] = { vertex: v }
125
+
126
+ memo
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,53 @@
1
+ require 'kantox/split/utils'
2
+
3
+ module Kantox
4
+ module Split
5
+ module Hooker
6
+ ACTIONS = [:create, :update, :destroy]
7
+
8
+ def self.included base
9
+ fail TypeError.new("Hooker may be included in «ActiveRecord::Base»d classes since it requires «after_commit» hook") unless base <= ::ActiveRecord::Base
10
+ base.include Kantox::Split::Utils
11
+ base.include InstanceMethods
12
+ base.extend ClassMethods
13
+
14
+ ACTIONS.each do |action|
15
+ base.after_commit "hooked_action_on_#{action}", on: action
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+ # @param hooks [Hash] the hash of `method: Handler`, e. g.:
21
+ # `{ create: CreateMapper, destroy: DestroyMapper }`.
22
+ # Each handler must implement contructor, receiving `ActiveRecord`,
23
+ # `#save`, `#update` and `#destroy` methods to store the content
24
+ # into splitted data store, and (optionally) `#to_hash` method,
25
+ # producing a hash to be splitted and stored.
26
+ def hook default_hooker = nil, **hooks
27
+ @split_hooks_on_commit ||= { hooker: default_hooker }
28
+ @split_hooks_on_commit.merge!(ACTIONS.map { |a| [a, default_hooker] }.to_h) if default_hooker
29
+ @split_hooks_on_commit.merge!(hooks)
30
+ if block_given?
31
+ yielder = Proc.new # reinstantiate &cb
32
+ @split_hooks_on_commit.values.uniq.each do |h|
33
+ h.config(&yielder) if h.respond_to? :config
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ module InstanceMethods
40
+ def hooks
41
+ lookup_variable(:split_hooks_on_commit)
42
+ end
43
+ private :hooks
44
+
45
+ ACTIONS.each do |action|
46
+ define_method "hooked_action_on_#{action}" do
47
+ hooks[action] && hooks[action].respond_to?(action) && hooks[action].public_send(action, self)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,62 @@
1
+ module Kantox
2
+ module Split
3
+ module Utils
4
+ class << self
5
+ def store_variable object, name, value
6
+ # FIXME
7
+ object.instance_variable_set :"@#{name}", value
8
+ object.class.instance_variable_set :"@#{name}", value
9
+ end
10
+ def lookup_variable object, name
11
+ return object.instance_variable_get(:"@#{name}") if object.instance_variable_defined?(:"@#{name}")
12
+ klazz = object.class
13
+ while klazz do
14
+ break klazz.instance_variable_get(:"@#{name}") if klazz.instance_variable_defined?(:"@#{name}")
15
+ klazz = klazz.superclass
16
+ end
17
+ end
18
+ def lookup_variable_value object, getter
19
+ case getter
20
+ when Array then getter.map { |v| lookup_variable_value object, v }
21
+ when Hash then getter.map { |k, v| [k, lookup_variable_value(object, v)] }.to_h
22
+ when String then object.instance_eval(getter) rescue nil
23
+ when Symbol then object.public_send(getter) rescue nil
24
+ when ->(p) { p.respond_to? :to_proc } then getter.to_proc.call(object) rescue nil
25
+ else raise ArgumentError.new "Expected Array, Hash, String, Symbol or Proc. Got: #{getter.class}"
26
+ end
27
+ end
28
+
29
+ def omnivorous_to_h obj, levels = 1, collected = [], default = nil
30
+ return default ? "∃#{instance_eval(default)}" : obj if collected.include? obj
31
+
32
+ levels < 0 ? obj :
33
+ case obj
34
+ when Array
35
+ obj.map { |e| omnivorous_to_h e, levels, collected, default }
36
+ when ->(o) { o.methods.include?(:to_h) && o.method(:to_h).parameters.map(&:first) == [:opt, :opt] }
37
+ obj.to_h levels - 1, collected << obj
38
+ else
39
+ obj
40
+ end
41
+ end
42
+ end
43
+
44
+ def self.included base
45
+ base.extend ClassMethods
46
+ end
47
+
48
+ module ClassMethods
49
+ def store_variable name, value
50
+ Utils.store_variable self, name, value
51
+ end
52
+ end
53
+
54
+ def lookup_variable name
55
+ Utils.lookup_variable self, name
56
+ end
57
+ def lookup_variable_value name
58
+ Utils.lookup_variable_value self, name
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ module Kantox
2
+ module Split
3
+ VERSION = "0.2.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kantox-split
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Kantox LTD
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rgl
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: kungfuig
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.12'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: cucumber
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: yard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: This gem is extremely useful while in process of migration to another
112
+ data source.
113
+ email:
114
+ - aleksei.matiushkin@kantox.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - ".rspec"
121
+ - ".rubocop.yml"
122
+ - ".rubocop_todo.yml"
123
+ - ".travis.yml"
124
+ - Gemfile
125
+ - README.md
126
+ - Rakefile
127
+ - bin/console
128
+ - bin/setup
129
+ - kantox-split.gemspec
130
+ - lib/kantox/split.rb
131
+ - lib/kantox/split/adapters.rb
132
+ - lib/kantox/split/adapters/getters.rb
133
+ - lib/kantox/split/graph.rb
134
+ - lib/kantox/split/hooker.rb
135
+ - lib/kantox/split/utils.rb
136
+ - lib/kantox/split/version.rb
137
+ homepage: http://kantox.com
138
+ licenses: []
139
+ metadata: {}
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 2.4.8
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: Easy split ActiveRecord’s CUD operations to write to separate data source.
160
+ test_files: []
161
+ has_rdoc: