narabikae 0.2.0 → 0.3.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: 96e657bcc111a885f21934870ac5360490aa4999b6df0533af524f761ecd9244
4
- data.tar.gz: d7eca3f77b6260eea610bb5f5dbcdd71099972f74cd88028d00c5a266bd32667
3
+ metadata.gz: 889a0fb05988806d1ff5ab57e02932cf4bf8a57ad788e3a4f094456e15e57902
4
+ data.tar.gz: 1dfb405bc128aacd6bae61b89e133af0aa40cf67b16638ba475bb1933584c855
5
5
  SHA512:
6
- metadata.gz: e0bcec0651250189dcdac6c724bccf994d98350d4668e543dab8e039cc3f5ecd2891961ba2ecaa3d9bcd198094968137d4d5fb8215f7da692a849496b310cec7
7
- data.tar.gz: 90aa217d0d397c49452febff37a6153ffc10c2f309de27348482b1f28a3dac58440306001f2110eb70c3fa063e1d3e2789846b4c5fe0377750c84260b70a2e2b
6
+ metadata.gz: 0c2e99432062adc3745d8c6641d99bbd7a2b91a021103c552f3c4f9a7d6678370c344af81adf7d10a0ba3103730070bd8f7370fcb9c99a99dd06c8d01d89e882
7
+ data.tar.gz: 0aed46f7bf0ed8ae057324e17b99799d132e77244382ba0d945476221d3edb0d7c2f9444f2281b0d28a9e85e17fce9da1cb0eba13c27c613e4e4fe5da629bdaa
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Narabikae
2
2
 
3
+ [![test](https://github.com/kazu-2020/narabikae/actions/workflows/ci.yaml/badge.svg?branch=main&event=push)](https://github.com/kazu-2020/narabikae/actions/workflows/ci.yaml)
4
+
3
5
  Narabikae(Japanese: 並び替え) means "reorder". Like [acts_as_list](https://github.com/brendon/acts_as_list), this gem provides automatic order management and reordering functionality for your records.
4
6
 
5
7
  One of the key advantages of this gem is its use of the [fractional indexing algorithm](https://www.figma.com/blog/realtime-editing-of-ordered-sequences/#fractional-indexing), which greatly enhances the efficiency of reordering operations. With Narabikae, regardless of the amount of data, "only a single record" is updated during the reordering process 🎉.
@@ -67,6 +69,10 @@ class Task < ApplicationRecord
67
69
  # Used for validation of the internally generated order value.
68
70
  # This value should be equivalent to
69
71
  # the limit set in the DB column.
72
+ #
73
+ # default_position: optional
74
+ # Set where new/auto-set records are inserted.
75
+ # Accepts :first or :last (default).
70
76
  end
71
77
  ```
72
78
 
@@ -79,13 +85,23 @@ Task.create([
79
85
  { name: 'task-3' }
80
86
  ])
81
87
  Task.order(:position).pluck(:name, :position)
82
- # => [["task-1", "a0"], ["task-3", "a1"], ["task-1", "a2"]]
88
+ # => [["task-1", "a0"], ["task-2", "a1"], ["task-3", "a2"]]
83
89
 
84
90
  ```
85
91
 
86
92
  > [!NOTE]
87
93
  > The position is set using the before_create callback. Therefore, do not define validations such as presence on the attributes managed by this gem!
88
94
 
95
+ #### Default position
96
+
97
+ By default, new/auto-set records are inserted at the end of the list. To insert at the beginning instead:
98
+
99
+ ```rb
100
+ class Task < ApplicationRecord
101
+ narabikae :position, size: 200, default_position: :first
102
+ end
103
+ ```
104
+
89
105
  ## Usage Details
90
106
 
91
107
  ### Reorder
@@ -155,6 +171,45 @@ target.position
155
171
  # ex: target.move_to_position_between(tasks.first, nil)
156
172
  ```
157
173
 
174
+ ### Set without saving
175
+
176
+ If you want to set the new position value and save later (for example, in a form), use `set_<field>_after/before/between`. These methods only assign the new position value and do not persist the record.
177
+
178
+ ```ruby
179
+ target.set_position_after(tasks.last)
180
+ target.position
181
+ # => 'a3'
182
+ target.save
183
+ ```
184
+
185
+ You can also use setter-style aliases:
186
+
187
+ ```ruby
188
+ target.position_after = tasks.last
189
+ target.position_between = [tasks.first, tasks.last]
190
+ ```
191
+
192
+ #### Form-friendly setters
193
+
194
+ The setter aliases can be used directly in forms or `assign_attributes`. They accept a target record or a position key (string). For `*_between=`, you can pass an array or hash. Primary key inputs are not accepted; do your own lookup and pass the record or its position.
195
+
196
+ ```ruby
197
+ # position key input (e.g., from a hidden field)
198
+ task.assign_attributes(position_after: tasks.last.position)
199
+
200
+ # between using an array
201
+ task.position_between = [tasks.first, tasks.last]
202
+
203
+ # between using a hash (string or symbol keys)
204
+ task.position_between = { prev: tasks.first.position, next: tasks.last.position }
205
+ ```
206
+
207
+ If you need retries, use the method form and pass `challenge` there:
208
+
209
+ ```ruby
210
+ task.set_position_between(tasks.first, tasks.last, challenge: 15)
211
+ ```
212
+
158
213
  ### Scope
159
214
 
160
215
  You can use this when you want to manage independent positions within specific scopes, such as foreign keys.
@@ -168,7 +223,7 @@ end
168
223
  class Chapter < ApplicationRecord
169
224
  belongs_to :course
170
225
 
171
- narabikae :position, size: 100, scope: %i[course_id]
226
+ narabikae :position, size: 100, scope: :course_id
172
227
  end
173
228
 
174
229
  course = Course.create
@@ -214,6 +269,53 @@ ticket.move_to_position_between(t1, t2, challenge: 15)
214
269
 
215
270
  Feel free to message me on Github (kazu-2020)
216
271
 
272
+ ## Development
273
+
274
+ ### Supported versions (tested in CI)
275
+
276
+ - Ruby 3.1, 3.2, 3.3, 3.4, 4.0
277
+ - Rails 7.1, 7.2, 8.0, 8.1, and Rails main (via `railties` from `rails/rails`)
278
+
279
+ ### Test suite
280
+
281
+ Tests are Minitest-based and run against a dummy Rails app located at `test/dummy`.
282
+
283
+ Database targets:
284
+
285
+ - `TARGET_DB=mysql` (default)
286
+ - `TARGET_DB=postgres`
287
+ - `TARGET_DB=sqlite`
288
+
289
+ To spin up database services locally:
290
+
291
+ ```sh
292
+ docker compose up -d
293
+ ```
294
+
295
+ Run the full matrix locally (all databases):
296
+
297
+ ```sh
298
+ bundle exec rake test
299
+ ```
300
+
301
+ Run a single database:
302
+
303
+ ```sh
304
+ bundle exec rake test:postgres
305
+ ```
306
+
307
+ Run tests directly with Rails for a specific target:
308
+
309
+ ```sh
310
+ TARGET_DB=sqlite bin/rails test
311
+ ```
312
+
313
+ To test against a specific Rails version:
314
+
315
+ ```sh
316
+ BUNDLE_GEMFILE=gemfiles/rails_8_1.gemfile TARGET_DB=mysql bundle exec rake test
317
+ ```
318
+
217
319
  ## Contributing
218
320
 
219
321
  Please wait a moment... 🙏
@@ -11,36 +11,60 @@ module Narabikae
11
11
  # check valid key for fractional_indexer
12
12
  # when invalid key, raise FractionalIndexer::Error
13
13
  FractionalIndexer.generate_key(prev_key: record.send(option.field))
14
- option.scope.any? { |s| record.will_save_change_to_attribute?(s) } && !record.will_save_change_to_attribute?(option.field)
14
+ record.send(option.field).nil? ||
15
+ (option.scope.any? { |s| record.will_save_change_to_attribute?(s) } && !record.will_save_change_to_attribute?(option.field))
15
16
  rescue FractionalIndexer::Error
16
17
  true
17
18
  end
18
19
 
19
- def set_position
20
- record.send("#{option.field}=", position_generator.create_last_position)
20
+ def set_position(position = option.default_position)
21
+ new_position =
22
+ case position
23
+ when :first
24
+ position_generator.create_first_position
25
+ when :last
26
+ position_generator.create_last_position
27
+ end
28
+
29
+ record.send("#{option.field}=", new_position)
21
30
  end
22
31
 
23
- def move_to_after(target, **args)
32
+ def set_after(target, **args)
24
33
  new_position = position_generator.find_position_after(target, **args)
25
34
  return false if new_position.blank?
26
35
 
27
36
  record.send("#{option.field}=", new_position)
28
- record.save
29
37
  end
30
38
 
31
- def move_to_before(target, **args)
39
+ def set_before(target, **args)
32
40
  new_position = position_generator.find_position_before(target, **args)
33
41
  return false if new_position.blank?
34
42
 
35
43
  record.send("#{option.field}=", new_position)
36
- record.save
37
44
  end
38
45
 
39
- def move_to_between(prev_target, next_target, **args)
46
+ def set_between(prev_target, next_target, **args)
40
47
  new_position = position_generator.find_position_between(prev_target, next_target, **args)
41
48
  return false if new_position.blank?
42
49
 
43
50
  record.send("#{option.field}=", new_position)
51
+ end
52
+
53
+ def move_to_after(target, **args)
54
+ return false unless set_after(target, **args)
55
+
56
+ record.save
57
+ end
58
+
59
+ def move_to_before(target, **args)
60
+ return false unless set_before(target, **args)
61
+
62
+ record.save
63
+ end
64
+
65
+ def move_to_between(prev_target, next_target, **args)
66
+ return false unless set_between(prev_target, next_target, **args)
67
+
44
68
  record.save
45
69
  end
46
70
 
@@ -2,7 +2,7 @@ module Narabikae
2
2
  class Configuration
3
3
  # Sets the base value for FractionalIndexer configuration.
4
4
  #
5
- # @param int [Integer] The base value can be 10, 62, 94, with the default being 94.
5
+ # @param int [Integer] The base value can be 10, 62, 94, with the default being 62.
6
6
  # @return [void]
7
7
  def base=(int)
8
8
  FractionalIndexer.configure do |config|
@@ -1,16 +1,22 @@
1
1
  module Narabikae
2
2
  class Option
3
- attr_reader :field, :key_max_size, :scope
3
+ attr_reader :field, :key_max_size, :scope, :default_position
4
4
 
5
5
  # Initializes a new instance of the Option class.
6
6
  #
7
7
  # @param field [Symbol]
8
8
  # @param key_max_size [Integer] The maximum size of the key.
9
- # @param scope [Array<Symbol>] The scope of the option.
10
- def initialize(field:, key_max_size:, scope: [])
9
+ # @param scope [Symbol, Array<Symbol>] The scope of the option.
10
+ # @param default_position [Symbol] The default position when creating or auto setting.
11
+ def initialize(field:, key_max_size:, scope: [], default_position: :last)
11
12
  @field = field.to_sym
12
13
  @key_max_size = key_max_size.to_i
13
- @scope = scope.is_a?(Array) ? scope.map(&:to_sym) : []
14
+ @scope = Array.wrap(scope).map(&:to_sym)
15
+ @default_position = (default_position || :last).to_sym
16
+
17
+ unless %i[first last].include?(@default_position)
18
+ raise ArgumentError, "default_position must be :first or :last"
19
+ end
14
20
  end
15
21
  end
16
22
  end
@@ -16,24 +16,29 @@ module Narabikae
16
16
  FractionalIndexer.generate_key(prev_key: current_last_position)
17
17
  end
18
18
 
19
+ # Generates a new key for the first position
20
+ #
21
+ # @return [String] The newly generated key for the first position.
22
+ def create_first_position
23
+ FractionalIndexer.generate_key(next_key: current_first_position)
24
+ end
25
+
19
26
  # Finds the position after the specified target.
20
27
  # If generated key is invalid(ex: it already exists),
21
28
  # a new key is generated until the challenge count reaches the limit.
22
29
  # challenge count is 10 by default.
23
30
  #
24
- # @param target [#send(field)]
25
- # @param args [Hash] Additional arguments.
26
- # @option args [Integer] :challenge The number of times to attempt finding a valid position.
31
+ # @param target [ActiveRecord::Base, String]
32
+ # @param challenge [Integer] The number of times to attempt finding a valid position.
27
33
  # @return [String, nil] The generated key for the position after the target, or nil if no valid position is found.
28
- def find_position_after(target, **args)
29
- merged_args = { challenge: 10 }.merge(args)
34
+ def find_position_after(target, challenge: 10)
30
35
  # when target is nil, try to generate key from the last position
31
- key = FractionalIndexer.generate_key(
32
- prev_key: target&.send(option.field) || current_last_position
33
- )
36
+ target_key = extract_target_key(target) || current_last_position
37
+ key = FractionalIndexer.generate_key(prev_key: target_key)
34
38
  return key if valid?(key)
35
39
 
36
- (merged_args[:challenge] || 0).times do
40
+ (challenge || 0).times do |i|
41
+ key = FractionalIndexer.generate_key(prev_key: target_key, next_key: key)
37
42
  key += random_fractional
38
43
  return key if valid?(key)
39
44
  end
@@ -53,19 +58,17 @@ module Narabikae
53
58
  # position = Position.new
54
59
  # position.find_position_before(target, challenge: 5)
55
60
  #
56
- # @param target [#send(field)]
57
- # @param args [Hash] Additional arguments.
58
- # @option args [Integer] :challenge The number of times to attempt finding a valid position.
61
+ # @param target [ActiveRecord::Base, String]
62
+ # @param challenge [Integer] The number of times to attempt finding a valid position.
59
63
  # @return [String, nil] The generated key for the position before the target, or nil if no valid position is found.
60
- def find_position_before(target, **args)
61
- merged_args = { challenge: 10 }.merge(args)
64
+ def find_position_before(target, challenge: 10)
62
65
  # when target is nil, try to generate key from the first position
63
- key = FractionalIndexer.generate_key(
64
- next_key: target&.send(option.field) || current_first_position
65
- )
66
+ target_key = extract_target_key(target) || current_first_position
67
+ key = FractionalIndexer.generate_key(next_key: target_key)
66
68
  return key if valid?(key)
67
69
 
68
- (merged_args[:challenge] || 0).times do
70
+ (challenge || 0).times do |i|
71
+ key = FractionalIndexer.generate_key(prev_key: key, next_key: target_key)
69
72
  key += random_fractional
70
73
  return key if valid?(key)
71
74
  end
@@ -77,25 +80,25 @@ module Narabikae
77
80
 
78
81
  # Finds the position between two targets.
79
82
  #
80
- # @param prev_target [#send(field)] The previous target.
81
- # @param next_target [#send(field)] The next target.
82
- # @param args [Hash] Additional arguments.
83
- # @option args [Integer] :challenge The number of times to attempt finding a valid position.
83
+ # @param prev_target [ActiveRecord::Base, String] The previous target.
84
+ # @param next_target [ActiveRecord::Base, String] The next target.
85
+ # @param challenge [Integer] The number of times to attempt finding a valid position.
84
86
  # @return [string, nil] The position between the two targets, or nil if no valid position is found.
85
- def find_position_between(prev_target, next_target, **args)
86
- return find_position_before(next_target, **args) if prev_target.blank?
87
- return find_position_after(prev_target, **args) if next_target.blank?
88
-
89
- merged_args = { challenge: 10 }.merge(args)
87
+ def find_position_between(prev_target, next_target, challenge: 10)
88
+ prev_key = extract_target_key(prev_target)
89
+ next_key = extract_target_key(next_target)
90
+ return find_position_before(next_target, challenge: challenge) if prev_key.blank?
91
+ return find_position_after(prev_target, challenge: challenge) if next_key.blank?
90
92
 
91
- prev_key, next_key = [ prev_target.send(option.field), next_target.send(option.field) ].minmax
93
+ prev_key, next_key = [ prev_key, next_key ].minmax
92
94
  key = FractionalIndexer.generate_key(
93
95
  prev_key: prev_key,
94
96
  next_key: next_key,
95
97
  )
96
98
  return key if valid?(key)
97
99
 
98
- (merged_args[:challenge] || 0).times do
100
+ (challenge || 0).times do |i|
101
+ key = FractionalIndexer.generate_key(prev_key: key, next_key: next_key)
99
102
  key += random_fractional
100
103
  return key if valid?(key)
101
104
  end
@@ -122,7 +125,7 @@ module Narabikae
122
125
  end
123
126
 
124
127
  def model
125
- record.class.base_class
128
+ record.class.base_class.unscoped
126
129
  end
127
130
 
128
131
  # generate a random fractional part
@@ -147,5 +150,43 @@ module Narabikae
147
150
 
148
151
  capable?(key) && uniq?(key)
149
152
  end
153
+
154
+ def extract_target_key(target)
155
+ return if target.nil?
156
+ return target if target.is_a?(String)
157
+ unless target.is_a?(ActiveRecord::Base)
158
+ raise Narabikae::Error, "target must be an ActiveRecord object or position key string"
159
+ end
160
+
161
+ record_table = table_name_for_class(record)
162
+ target_table = table_name_for_class(target)
163
+ unless target_table && record_table && target_table == record_table
164
+ raise Narabikae::Error,
165
+ "target model mismatch: expected table #{record_table || 'unknown'}, got #{target_table || 'unknown'}"
166
+ end
167
+
168
+ mismatched_columns = mismatched_scope_columns(target)
169
+ if mismatched_columns.any?
170
+ raise Narabikae::Error, "target scope mismatch for columns: #{mismatched_columns.join(', ')}"
171
+ end
172
+ raise Narabikae::Error, "target missing #{option.field} field" unless target.respond_to?(option.field)
173
+
174
+ target.send(option.field)
175
+ end
176
+
177
+ def table_name_for_class(value)
178
+ klass = value.class
179
+ return unless klass.respond_to?(:table_name)
180
+
181
+ klass.table_name
182
+ end
183
+
184
+ def mismatched_scope_columns(target)
185
+ option.scope.select do |column|
186
+ !target.respond_to?(column) ||
187
+ !record.respond_to?(column) ||
188
+ target.public_send(column) != record.public_send(column)
189
+ end
190
+ end
150
191
  end
151
192
  end
@@ -1,3 +1,3 @@
1
1
  module Narabikae
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/narabikae.rb CHANGED
@@ -29,20 +29,50 @@ module Narabikae
29
29
  extend ActiveSupport::Concern
30
30
 
31
31
  class_methods do
32
- def narabikae(field = :position, size:, scope: [])
32
+ def narabikae(field = :position, size:, scope: [], default_position: :last)
33
33
  option = narabikae_option_store.register!(
34
34
  field.to_sym,
35
- Narabikae::Option.new(field: field, key_max_size: size, scope: scope)
35
+ Narabikae::Option.new(field: field, key_max_size: size, scope: scope, default_position: default_position)
36
36
  )
37
37
 
38
- before_create do
38
+ before_save -> {
39
39
  extension = Narabikae::ActiveRecordExtension.new(self, option)
40
- extension.set_position
40
+ extension.set_position(option.default_position) if extension.auto_set_position?
41
+ }
42
+
43
+ define_method :"set_#{field}_after" do |target = nil, **args|
44
+ extension = Narabikae::ActiveRecordExtension.new(self, option)
45
+ extension.set_after(target, **args)
46
+ end
47
+ alias_method :"#{field}_after=", :"set_#{field}_after"
48
+
49
+ define_method :"set_#{field}_before" do |target = nil, **args|
50
+ extension = Narabikae::ActiveRecordExtension.new(self, option)
51
+ extension.set_before(target, **args)
52
+ end
53
+ alias_method :"#{field}_before=", :"set_#{field}_before"
54
+
55
+ define_method :"set_#{field}_between" do |prev_target = nil, next_target = nil, **args|
56
+ extension = Narabikae::ActiveRecordExtension.new(self, option)
57
+ extension.set_between(prev_target, next_target, **args)
41
58
  end
59
+ define_method :"#{field}_between=" do |value|
60
+ prev_target = nil
61
+ next_target = nil
62
+
63
+ case value
64
+ when Array
65
+ prev_target, next_target = value
66
+ when Hash
67
+ payload = value.with_indifferent_access
68
+ prev_target = payload[:prev_target] || payload[:prev]
69
+ next_target = payload[:next_target] || payload[:next]
70
+ else
71
+ prev_target = value
72
+ end
42
73
 
43
- before_update do
44
74
  extension = Narabikae::ActiveRecordExtension.new(self, option)
45
- extension.set_position if extension.auto_set_position?
75
+ extension.set_between(prev_target, next_target)
46
76
  end
47
77
 
48
78
  define_method :"move_to_#{field}_after" do |target = nil, **args|
metadata CHANGED
@@ -1,37 +1,106 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: narabikae
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - matazou
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-02 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activerecord
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: railties
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.1'
13
40
  - !ruby/object:Gem::Dependency
14
41
  name: fractional_indexer
15
42
  requirement: !ruby/object:Gem::Requirement
16
43
  requirements:
17
44
  - - ">="
18
45
  - !ruby/object:Gem::Version
19
- version: '0'
46
+ version: 0.4.0
20
47
  type: :runtime
21
48
  prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.4.0
54
+ - !ruby/object:Gem::Dependency
55
+ name: appraisal
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
22
63
  version_requirements: !ruby/object:Gem::Requirement
23
64
  requirements:
24
65
  - - ">="
25
66
  - !ruby/object:Gem::Version
26
67
  version: '0'
27
68
  - !ruby/object:Gem::Dependency
28
- name: activerecord
69
+ name: debug
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.9'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.9'
82
+ - !ruby/object:Gem::Dependency
83
+ name: minitest
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '5.0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '5.0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: mocha
29
98
  requirement: !ruby/object:Gem::Requirement
30
99
  requirements:
31
100
  - - ">="
32
101
  - !ruby/object:Gem::Version
33
102
  version: '0'
34
- type: :runtime
103
+ type: :development
35
104
  prerelease: false
36
105
  version_requirements: !ruby/object:Gem::Requirement
37
106
  requirements:
@@ -39,13 +108,13 @@ dependencies:
39
108
  - !ruby/object:Gem::Version
40
109
  version: '0'
41
110
  - !ruby/object:Gem::Dependency
42
- name: activesupport
111
+ name: mysql2
43
112
  requirement: !ruby/object:Gem::Requirement
44
113
  requirements:
45
114
  - - ">="
46
115
  - !ruby/object:Gem::Version
47
116
  version: '0'
48
- type: :runtime
117
+ type: :development
49
118
  prerelease: false
50
119
  version_requirements: !ruby/object:Gem::Requirement
51
120
  requirements:
@@ -53,21 +122,21 @@ dependencies:
53
122
  - !ruby/object:Gem::Version
54
123
  version: '0'
55
124
  - !ruby/object:Gem::Dependency
56
- name: rspec-rails
125
+ name: pg
57
126
  requirement: !ruby/object:Gem::Requirement
58
127
  requirements:
59
128
  - - ">="
60
129
  - !ruby/object:Gem::Version
61
- version: 5.0.0
130
+ version: '0'
62
131
  type: :development
63
132
  prerelease: false
64
133
  version_requirements: !ruby/object:Gem::Requirement
65
134
  requirements:
66
135
  - - ">="
67
136
  - !ruby/object:Gem::Version
68
- version: 5.0.0
137
+ version: '0'
69
138
  - !ruby/object:Gem::Dependency
70
- name: rubocop-rails-omakase
139
+ name: sqlite3
71
140
  requirement: !ruby/object:Gem::Requirement
72
141
  requirements:
73
142
  - - ">="
@@ -81,7 +150,7 @@ dependencies:
81
150
  - !ruby/object:Gem::Version
82
151
  version: '0'
83
152
  - !ruby/object:Gem::Dependency
84
- name: rubocop-rspec
153
+ name: rubocop-rails-omakase
85
154
  requirement: !ruby/object:Gem::Requirement
86
155
  requirements:
87
156
  - - ">="
@@ -109,7 +178,6 @@ files:
109
178
  - README.md
110
179
  - lib/narabikae.rb
111
180
  - lib/narabikae/active_record_extension.rb
112
- - lib/narabikae/active_record_handler.rb
113
181
  - lib/narabikae/configuration.rb
114
182
  - lib/narabikae/option.rb
115
183
  - lib/narabikae/option_store.rb
@@ -125,7 +193,6 @@ metadata:
125
193
  source_code_uri: https://github.com/kazu-2020/narabikae
126
194
  allowed_push_host: https://rubygems.org/
127
195
  rubygems_mfa_required: 'true'
128
- post_install_message:
129
196
  rdoc_options: []
130
197
  require_paths:
131
198
  - lib
@@ -133,15 +200,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
200
  requirements:
134
201
  - - ">="
135
202
  - !ruby/object:Gem::Version
136
- version: '0'
203
+ version: '3.1'
137
204
  required_rubygems_version: !ruby/object:Gem::Requirement
138
205
  requirements:
139
206
  - - ">="
140
207
  - !ruby/object:Gem::Version
141
208
  version: '0'
142
209
  requirements: []
143
- rubygems_version: 3.5.9
144
- signing_key:
210
+ rubygems_version: 3.6.7
145
211
  specification_version: 4
146
212
  summary: provides simple position management and sorting functionality for Active
147
213
  Record in Rails.
@@ -1,31 +0,0 @@
1
- module Narabikae
2
- class ActiveRecordHandler
3
- # Initializes a new instance of the ActiveRecordHandler class.
4
- #
5
- # @param record [Object] The ActiveRecord object.
6
- # @param column [Symbol] The column symbol.
7
- def initialize(record, column)
8
- @record = record
9
- @column = column
10
- end
11
-
12
- # Generates a new key for the last position
13
- #
14
- # @return [String] The newly generated key for the last position.
15
- def create_last_position
16
- FractionalIndexer.generate_key(prev_key: current_last_position)
17
- end
18
-
19
- private
20
-
21
- attr_reader :record, :column
22
-
23
- def current_last_position
24
- model.maximum(column)
25
- end
26
-
27
- def model
28
- record.class.base_class
29
- end
30
- end
31
- end