activekit 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/active_kit/attribute.rb +10 -0
- data/lib/active_kit/activekitable.rb +16 -0
- data/lib/active_kit/activekiter.rb +11 -0
- data/lib/active_kit/engine.rb +3 -3
- data/lib/active_kit/loader.rb +23 -0
- data/lib/active_kit/relation.rb +7 -0
- data/lib/active_kit/sequence/sequence.rb +37 -0
- data/lib/active_kit/sequence/sequenceable.rb +22 -37
- data/lib/active_kit/sequence.rb +8 -0
- data/lib/active_kit/version.rb +1 -1
- data/lib/active_kit.rb +4 -2
- metadata +7 -2
- data/lib/active_kit/sequence/sequencer.rb +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98f08d0d1d37f5f2e3968da22af8cb3feb20704f5f5f6c6cf02d838fd2560354
|
4
|
+
data.tar.gz: ee3805f8d06d399c9519d0ae0360ee07f1069400033638eea6c2f9cfce519aac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6dc11428da73f1875bec2250f402df9e67053903b5b6c1762190fcf72f3c16d8f76f42c34bfcd34d9b9b5ecdf534d8d71d6bafbcd059dfe1c968652bfc8490f2
|
7
|
+
data.tar.gz: 73521d96b3200bbeaae1edda274ed4eff23154b66c8206b888b3ce540eb55d92a351925c628e4e4bcbbcfe3f007a23a945e12fbda6581c233d199b7a26150cae
|
@@ -2,6 +2,16 @@ module ActiveKit
|
|
2
2
|
class Attribute < ApplicationRecord
|
3
3
|
belongs_to :record, polymorphic: true
|
4
4
|
|
5
|
+
store :value, accessors: [ :sequence ], coder: JSON
|
6
|
+
|
5
7
|
validates :value, presence: true, length: { maximum: 1073741823, allow_blank: true }
|
8
|
+
|
9
|
+
before_validation :set_defaults
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def set_defaults
|
14
|
+
self.sequence = { attributes: {} } if self.sequence.blank?
|
15
|
+
end
|
6
16
|
end
|
7
17
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require "active_kit/sequence/sequenceable"
|
3
|
+
|
4
|
+
module ActiveKit
|
5
|
+
module Activekitable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include ActiveKit::Loader
|
8
|
+
include ActiveKit::Sequence::Sequenceable
|
9
|
+
|
10
|
+
included do
|
11
|
+
end
|
12
|
+
|
13
|
+
class_methods do
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/active_kit/engine.rb
CHANGED
@@ -3,11 +3,11 @@ module ActiveKit
|
|
3
3
|
isolate_namespace ActiveKit
|
4
4
|
config.eager_load_namespaces << ActiveKit
|
5
5
|
|
6
|
-
initializer "active_kit.
|
7
|
-
require "active_kit/
|
6
|
+
initializer "active_kit.activekitable" do
|
7
|
+
require "active_kit/activekitable"
|
8
8
|
|
9
9
|
ActiveSupport.on_load(:active_record) do
|
10
|
-
include ActiveKit::
|
10
|
+
include ActiveKit::Activekitable
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveKit
|
2
|
+
module Loader
|
3
|
+
def self.ensure_setup_for!(current_class:)
|
4
|
+
current_class.class_eval do
|
5
|
+
unless self.reflect_on_association :activekit_association
|
6
|
+
has_one :activekit_association, as: :record, dependent: :destroy, class_name: "ActiveKit::Attribute"
|
7
|
+
|
8
|
+
def activekit
|
9
|
+
@activekit ||= Relation.new(current_object: self)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.activekiter
|
13
|
+
@activekiter ||= Activekiter.new(current_class: self)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.ensure_has_one_association_for!(record:)
|
20
|
+
record.create_activekit_association unless record.activekit_association
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ActiveKit
|
2
|
+
module Sequence
|
3
|
+
class Sequence
|
4
|
+
attr_reader :defined_attributes
|
5
|
+
|
6
|
+
def initialize(current_class:)
|
7
|
+
@current_class = current_class
|
8
|
+
|
9
|
+
@defined_attributes = {}
|
10
|
+
@wordbook = Wordbook.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def update(record:, attribute_name:, position:)
|
14
|
+
ActiveKit::Loader.ensure_has_one_association_for!(record: record)
|
15
|
+
|
16
|
+
if position
|
17
|
+
raise "position '#{position}' is not a valid unsigned integer value greater than 0." unless position.is_a?(Integer) && position > 0
|
18
|
+
|
19
|
+
wordbook = Wordbook.new
|
20
|
+
word_for_position = wordbook.next_word(count: position)
|
21
|
+
json_where = 'value->"$.sequence.attributes.' + attribute_name.to_s + '" = "' + word_for_position + '"'
|
22
|
+
record_at_position = ActiveKit::Attribute.where(record_type: record.class.name).where(json_where).first&.record
|
23
|
+
record.activekit_association.sequence[:attributes][attribute_name.to_sym] = word_for_position
|
24
|
+
record.activekit_association.save!
|
25
|
+
record_at_position.save! if record_at_position
|
26
|
+
else
|
27
|
+
record.activekit_association.sequence[:attributes][attribute_name.to_sym] = nil
|
28
|
+
record.activekit_association.save!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_attribute(name:, options:)
|
33
|
+
@defined_attributes.store(name, options)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -17,40 +17,25 @@ module ActiveKit
|
|
17
17
|
# sequence_attribute :name, :positioning_method, updater: { via: :assoc, on: {} }
|
18
18
|
# sequence_attribute :name, :positioning_method, updater: { via: {}, on: {} }
|
19
19
|
# Note: :on and :via in :updater can accept nested associations.
|
20
|
-
def sequence_attribute(name, positioning_method, **options)
|
20
|
+
def sequence_attribute(name, positioning_method = nil, **options)
|
21
|
+
ActiveKit::Loader.ensure_setup_for!(current_class: self)
|
22
|
+
|
21
23
|
name = name.to_sym
|
22
|
-
positioning_method
|
24
|
+
options.store(:positioning_method, positioning_method&.to_sym)
|
23
25
|
options.deep_symbolize_keys!
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
@sequencer ||= ActiveSequence::Sequencer.new(current_class: self)
|
28
|
-
end
|
29
|
-
|
30
|
-
has_many :sequence_attributes, as: :record, dependent: :destroy, class_name: "ActiveSequence::Attribute"
|
31
|
-
# scope :order_sequence, -> (options_hash) { includes(:sequence_attributes).where(sequence_attributes: { name: name.to_s }).order("sequence_attributes.value": :asc) }
|
32
|
-
end
|
33
|
-
|
34
|
-
set_active_sequence_create_callbacks(attribute_name: name)
|
35
|
-
set_active_sequence_commit_callbacks(attribute_name: name, positioning_method: positioning_method, updater: options.delete(:updater))
|
36
|
-
|
37
|
-
sequencer.add_attribute(name: name, options: options)
|
27
|
+
set_active_sequence_callbacks(attribute_name: name, options: options)
|
28
|
+
activekiter.sequence.add_attribute(name: name, options: options)
|
38
29
|
end
|
39
30
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
logger.info "ActiveSequence - Creating Sequence attribute '#{attribute}' from #{self.class.name}: Done."
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def set_active_sequence_commit_callbacks(attribute_name:, positioning_method:, updater:)
|
48
|
-
updater = updater || {}
|
31
|
+
def set_active_sequence_callbacks(attribute_name:, options:)
|
32
|
+
positioning_method = options.dig(:positioning_method)
|
33
|
+
updater = options.dig(:updater) || {}
|
49
34
|
|
50
35
|
if updater.empty?
|
51
36
|
after_commit do
|
52
37
|
position = positioning_method ? self.public_send(positioning_method) : nil
|
53
|
-
self.class.
|
38
|
+
self.class.activekiter.sequence.update(record: self, attribute_name: attribute_name, position: position)
|
54
39
|
logger.info "ActiveSequence - Sequencing from #{self.class.name}: Done."
|
55
40
|
end
|
56
41
|
else
|
@@ -61,20 +46,20 @@ module ActiveKit
|
|
61
46
|
updater_via = updater.delete(:via)
|
62
47
|
updater_on = updater.delete(:on) || updater
|
63
48
|
|
64
|
-
base_klass = search_base_klass(self.
|
65
|
-
klass = reflected_klass(base_klass, updater_on.
|
49
|
+
base_klass = search_base_klass(self.name, updater_via)
|
50
|
+
klass = reflected_klass(base_klass, updater_on.keys.first)
|
66
51
|
klass.constantize.class_eval do
|
67
52
|
after_commit do
|
68
|
-
inverse_assoc = search_inverse_assoc(self, updater_on)
|
53
|
+
inverse_assoc = self.class.search_inverse_assoc(self, updater_on)
|
69
54
|
position = positioning_method ? self.public_send(positioning_method) : nil
|
70
55
|
if inverse_assoc.respond_to?(:each)
|
71
|
-
inverse_assoc.each { |instance| instance.class.
|
56
|
+
inverse_assoc.each { |instance| instance.class.activekiter.sequence.update(record: instance, attribute_name: attribute_name, position: position) }
|
72
57
|
else
|
73
|
-
inverse_assoc.class.
|
58
|
+
inverse_assoc.class.activekiter.sequence.update(record: inverse_assoc, attribute_name: attribute_name, position: position)
|
74
59
|
end
|
75
60
|
logger.info "ActiveSequence - Sequencing from #{self.class.name}: Done."
|
76
61
|
end
|
77
|
-
end
|
62
|
+
end
|
78
63
|
end
|
79
64
|
end
|
80
65
|
|
@@ -84,8 +69,8 @@ module ActiveKit
|
|
84
69
|
elsif updater_via.is_a? Symbol
|
85
70
|
reflected_klass(classname, updater_via)
|
86
71
|
elsif updater_via.is_a? Hash
|
87
|
-
klass = reflected_klass(classname, updater_via.
|
88
|
-
updater_via.
|
72
|
+
klass = reflected_klass(classname, updater_via.keys.first)
|
73
|
+
updater_via.values.first.is_a?(Hash) ? search_base_klass(klass, updater_via.values.first) : reflected_klass(klass, updater_via.values.first)
|
89
74
|
end
|
90
75
|
end
|
91
76
|
|
@@ -96,11 +81,11 @@ module ActiveKit
|
|
96
81
|
end
|
97
82
|
|
98
83
|
def search_inverse_assoc(klass_object, updater_on)
|
99
|
-
if updater_on.
|
100
|
-
klass_object = klass_object.public_send(updater_on.
|
101
|
-
search_inverse_assoc(klass_object, updater_on.
|
84
|
+
if updater_on.values.first.is_a?(Hash)
|
85
|
+
klass_object = klass_object.public_send(updater_on.values.first.keys.first)
|
86
|
+
search_inverse_assoc(klass_object, updater_on.values.first)
|
102
87
|
else
|
103
|
-
klass_object.public_send(updater_on.
|
88
|
+
klass_object.public_send(updater_on.values.first)
|
104
89
|
end
|
105
90
|
end
|
106
91
|
end
|
data/lib/active_kit/version.rb
CHANGED
data/lib/active_kit.rb
CHANGED
@@ -4,6 +4,8 @@ require "active_kit/engine"
|
|
4
4
|
module ActiveKit
|
5
5
|
extend ActiveSupport::Autoload
|
6
6
|
|
7
|
-
autoload :
|
8
|
-
autoload :
|
7
|
+
autoload :Activekiter
|
8
|
+
autoload :Loader
|
9
|
+
autoload :Relation
|
10
|
+
autoload :Sequence
|
9
11
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activekit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- plainsource
|
@@ -52,9 +52,14 @@ files:
|
|
52
52
|
- config/routes.rb
|
53
53
|
- db/migrate/20231016050208_create_active_kit_attributes.rb
|
54
54
|
- lib/active_kit.rb
|
55
|
+
- lib/active_kit/activekitable.rb
|
56
|
+
- lib/active_kit/activekiter.rb
|
55
57
|
- lib/active_kit/engine.rb
|
58
|
+
- lib/active_kit/loader.rb
|
59
|
+
- lib/active_kit/relation.rb
|
60
|
+
- lib/active_kit/sequence.rb
|
61
|
+
- lib/active_kit/sequence/sequence.rb
|
56
62
|
- lib/active_kit/sequence/sequenceable.rb
|
57
|
-
- lib/active_kit/sequence/sequencer.rb
|
58
63
|
- lib/active_kit/sequence/wordbook.rb
|
59
64
|
- lib/active_kit/version.rb
|
60
65
|
- lib/activekit.rb
|
@@ -1,69 +0,0 @@
|
|
1
|
-
module ActiveKit
|
2
|
-
module Sequence
|
3
|
-
class Sequencer
|
4
|
-
attr_reader :defined_attributes
|
5
|
-
|
6
|
-
def initialize(current_class:)
|
7
|
-
@current_class = current_class
|
8
|
-
|
9
|
-
@defined_attributes = {}
|
10
|
-
@wordbook = Wordbook.new
|
11
|
-
end
|
12
|
-
|
13
|
-
def update(record:, attribute_name:, position:)
|
14
|
-
attribute = Attribute.find_by(record: record, name: attribute_name)
|
15
|
-
Attribute.create!(record: record, name: attribute_name) unless attribute
|
16
|
-
|
17
|
-
if position
|
18
|
-
raise "position '#{position}' is not a valid unsigned integer value greater than 0." unless position.is_a?(Integer) && position > 0
|
19
|
-
|
20
|
-
attribute_at_position = Attribute.where(record_type: record.class.name, name: attribute_name).order(value: :asc).offset(position - 1).limit(1)
|
21
|
-
attribute
|
22
|
-
|
23
|
-
wordbook = Wordbook.new
|
24
|
-
total_position_count = Attribute.where(record_type: record.class.name, name: attribute_name).order(value: :asc).count
|
25
|
-
if attribute == attribute_at_position(position)
|
26
|
-
return
|
27
|
-
elsif position == 1
|
28
|
-
|
29
|
-
elsif position == total_position_count
|
30
|
-
wordbook.bookmark = attribute_at_position(total_position_count).value
|
31
|
-
|
32
|
-
attribute.value = wordbook.next_word if wordbook.next_word?
|
33
|
-
attribute.save!
|
34
|
-
elsif position > total_position_count
|
35
|
-
maximum_word = Attribute.where(record_type: record.class.name, name: attribute_name).maximum(:value)
|
36
|
-
|
37
|
-
wordbook.bookmark = maximum_word
|
38
|
-
attribute.value = wordbook.next_word if wordbook.next_word?
|
39
|
-
attribute.save!
|
40
|
-
elsif position < total_position_count
|
41
|
-
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def rebalance_from(position:)
|
47
|
-
ActiveRecord::Base.transaction do
|
48
|
-
wordbook = Wordbook.new
|
49
|
-
Attribute.where(record_type: record.class.name, name: attribute_name).order(value: :asc).offset(position - 1).limit(1)
|
50
|
-
Attribute.where(record_type: record.class.name, name: attribute_name).order(value: :asc).offset(position - 1).each do |attribute|
|
51
|
-
wordbook.bookmark = attribute.value
|
52
|
-
raise "Could not find next word in wordbook while rebalancing" unless wordbook.next_word?
|
53
|
-
|
54
|
-
attribute.value = wordbook.next_word
|
55
|
-
attribute.save!
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def attribute_at_position(position)
|
61
|
-
Attribute.where(record_type: record.class.name, name: attribute_name).order(value: :asc).offset(position - 1).limit(1)
|
62
|
-
end
|
63
|
-
|
64
|
-
def add_attribute(name:, options:)
|
65
|
-
@defined_attributes.store(name, options)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|