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 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