activekit 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f22601f05c64e21478512fd85ac1ebf74afc91c517349793fc79bfad4f343952
4
- data.tar.gz: 3ed1dcb02993f21dd6cb582b2574652eb34a5107e4d70c456ba047391294a908
3
+ metadata.gz: 98f08d0d1d37f5f2e3968da22af8cb3feb20704f5f5f6c6cf02d838fd2560354
4
+ data.tar.gz: ee3805f8d06d399c9519d0ae0360ee07f1069400033638eea6c2f9cfce519aac
5
5
  SHA512:
6
- metadata.gz: 78245200325e89c2a78a83123c2874bb9163d2202fdf9719b62f60d9986274a6ddb9e1700801cb2d7be896aaff90d782f79e43c9e6681c8720192e14e4738acd
7
- data.tar.gz: d770761da113c6f859e04250a980f3c4416ff142702ab2f97b88ca32bc063cb4f32e9967e0fa2c2b4deac10e5d4d63c392e00c5462f31a586aefa355b3f87918
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
@@ -0,0 +1,11 @@
1
+ module ActiveKit
2
+ class Activekiter
3
+ def initialize(current_class:)
4
+ @current_class = current_class
5
+ end
6
+
7
+ def sequence
8
+ @sequence ||= ActiveKit::Sequence::Sequence.new(current_class: @current_class)
9
+ end
10
+ end
11
+ end
@@ -3,11 +3,11 @@ module ActiveKit
3
3
  isolate_namespace ActiveKit
4
4
  config.eager_load_namespaces << ActiveKit
5
5
 
6
- initializer "active_kit.sequence" do
7
- require "active_kit/sequence/sequenceable"
6
+ initializer "active_kit.activekitable" do
7
+ require "active_kit/activekitable"
8
8
 
9
9
  ActiveSupport.on_load(:active_record) do
10
- include ActiveKit::Sequence::Sequenceable
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,7 @@
1
+ module ActiveKit
2
+ class Relation
3
+ def initialize(current_object:)
4
+ @current_object = current_object
5
+ end
6
+ end
7
+ 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 = positioning_method.to_sym
24
+ options.store(:positioning_method, positioning_method&.to_sym)
23
25
  options.deep_symbolize_keys!
24
26
 
25
- unless self.respond_to?(:sequencer)
26
- define_singleton_method :sequencer do
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 set_active_sequence_create_callbacks(attribute_name:)
41
- before_create do
42
- self.sequence_attributes.find_or_initialize_by(name: attribute_name)
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.sequencer.update(record: self, attribute_name: attribute_name, position: position)
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.class.name, updater_via)
65
- klass = reflected_klass(base_klass, updater_on.key)
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.sequencer.update(record: instance, attribute_name: attribute_name, position: position) }
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.sequencer.update(record: inverse_assoc, attribute_name: attribute_name, position: position)
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.key)
88
- updater_via.value.is_a?(Hash) ? search_base_klass(klass, updater_via.value) : reflected_klass(klass, updater_via.value)
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.value.is_a?(Hash)
100
- klass_object = klass_object.public_send(updater_on.value.key)
101
- search_inverse_assoc(klass_object, updater_on.value)
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.value)
88
+ klass_object.public_send(updater_on.values.first)
104
89
  end
105
90
  end
106
91
  end
@@ -0,0 +1,8 @@
1
+ module ActiveKit
2
+ module Sequence
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Sequence
6
+ autoload :Wordbook
7
+ end
8
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveKit
2
- VERSION = '0.1.2'
2
+ VERSION = '0.2.0'
3
3
  end
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 :Sequencer, "active_kit/sequence/sequencer"
8
- autoload :Wordbook, "active_kit/sequence/wordbook"
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.1.2
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