acts_as_list_neo4j 0.0.1 → 0.0.2

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
  SHA1:
3
- metadata.gz: 050fd8d022e4af493a0873a9aca244732f626d3c
4
- data.tar.gz: 992d2fd686652c01d2aa10f8aa917fe840aca290
3
+ metadata.gz: 51bd009a704744c855690ff4be456c9e79b17a43
4
+ data.tar.gz: 5808e3f7f90457ac8b7330beca053c51cd6b6c54
5
5
  SHA512:
6
- metadata.gz: b8e6c2ec1eb66bffab468ea3fbcaea61e9fd704c547251a5e6687e2174d14acea8ed47fa93e70f3a2ecb5a63d6305c95b7b9f907d40cdf9c1a5554b1ad6fcfc3
7
- data.tar.gz: db41c24f202dcda6c7025e3e93c4ea577d42d241539a4b8816514af8e8663bb67975e62064ddb5d485c012133edc93857b6f40788a5c25b98f6512a42023316f
6
+ metadata.gz: c81840bc7330f3f45cc05a45d2ef828967e6452ca46f2a825b56a92dc6f0e35e5fa134bbece1500ca00efa2f18d3ae175a47633197d73be093e1c776a9edd602
7
+ data.tar.gz: 2a9050c2ae416ec315b252f6de037268bc04e3d89fdde295048b95c27bf50463e8aff677e654a91d9a8cf91572f53e66290e6ad5a8d7f1f3bfe8ff53c3e71acd
data/README.md CHANGED
@@ -67,7 +67,7 @@ item.move(:down) # moves one up (:lower and :down is the same) withi
67
67
  item.move(to: position) # moves item to a specific position.
68
68
  item.move(above: other) # moves item above the other item.*
69
69
  item.move(below: other)
70
- <pre>
70
+ </pre>
71
71
 
72
72
  ## Running the specs
73
73
 
@@ -0,0 +1,8 @@
1
+ require 'neo4j'
2
+ require 'neo4j/acts_as_list'
3
+
4
+ class Module
5
+ def act_as_list
6
+ send :include, ActsAsList::Neo4j
7
+ end
8
+ end
@@ -0,0 +1,436 @@
1
+ require 'neo4j'
2
+
3
+ module ActsAsList
4
+ module Neo4j
5
+ class << self
6
+ attr_accessor :default_position_column
7
+ end
8
+
9
+ def self.included(klass)
10
+ klass.extend InitializerMethods
11
+ key = default_position_column || :position
12
+ klass.property key, type: Integer
13
+ klass.acts_as_list column: key.to_s
14
+ end
15
+
16
+ module InitializerMethods
17
+ def acts_as_list(options = {})
18
+ configuration = { column: 'position' }
19
+ configuration.update(options) if options.is_a?(Hash)
20
+
21
+ if configuration[:scope]
22
+ configuration[:scope] = configuration[:scope].to_sym
23
+ configuration[:scope] = "#{configuration[:scope]}_id".intern if configuration[:scope].to_s !~ /_id$/
24
+ end
25
+
26
+ define_method :position_column do
27
+ configuration[:column].to_s
28
+ end
29
+
30
+ if !configuration[:scope]
31
+ define_method :scope_condition do
32
+ { "i.#{position_key} <>" => nil }
33
+ end
34
+ elsif configuration[:scope].is_a?(Symbol)
35
+ define_method :scope_condition do
36
+ { configuration[:scope] => self[configuration[:scope]] }
37
+ end
38
+ else
39
+ fail ArgumentError, 'acts_as_list must either take a valid :scope option or be in an embedded document and use the parent document as scope'
40
+ end
41
+
42
+ include InstanceMethods
43
+ include Fields
44
+ include Triggers
45
+ extend Fields
46
+ extend ClassMethods
47
+
48
+ before_create :init_list_item
49
+ end
50
+ end
51
+
52
+ module ClassMethods
53
+ def in_scope
54
+ where(scope_condition)
55
+ end
56
+
57
+ def move_commands(symbol)
58
+ case symbol
59
+ when :symbol
60
+ [:highest, :top, :lowest, :bottom, :up, :higher, :down, :lower]
61
+ when :hash
62
+ [:to, :above, :below]
63
+ else
64
+ fail ArgumentError, "no move_commands defined for: #{symbol}"
65
+ end
66
+ end
67
+ end
68
+
69
+ module InstanceMethods
70
+ def move command
71
+ if command.is_a? Symbol
72
+ case command
73
+ when :highest, :top
74
+ move_to_top
75
+ when :lowest, :bottom
76
+ move_to_bottom
77
+ when :up, :higher
78
+ move_higher
79
+ when :down, :lower
80
+ move_lower
81
+ else
82
+ fail ArgumentError, "unknown move command '#{command}', try one of #{self.class.move_commands_available}"
83
+ end
84
+ elsif command.is_a? Hash
85
+ other = command.values.first
86
+ cmd = command.keys.first
87
+ case cmd
88
+ when :to
89
+ move_to(other)
90
+ when :above
91
+ move_above(other)
92
+ when :below
93
+ move_below(other)
94
+ else
95
+ fail ArgumentError, "Hash command #{cmd.inspect} not valid, must be one of"
96
+ end
97
+ else
98
+ fail ArgumentError, "move command takes either a Symbol or Hash as an argument, not a #{command.class}"
99
+ end
100
+ end
101
+
102
+ def order_by_position(conditions, extras = [])
103
+ sub_collection = self_class_all_or_in_collection.where(stringify_conditions(conditions))
104
+ sub_collection = sub_collection.order_by("i.#{position_key}").pluck(:i)
105
+
106
+ sub_collection = sub_collection.order_by(extras) unless extras.empty?
107
+
108
+ sub_collection
109
+ end
110
+
111
+ # conditions, { position_column => 1 }
112
+ def do_decrement(conditions, _options)
113
+ self_class_all_or_in_collection.where(stringify_conditions(conditions)).pluck(:i).each do |item|
114
+ item.adjust_position(-1)
115
+ end
116
+ end
117
+
118
+ def do_increment(conditions, _options)
119
+ self_class_all_or_in_collection.where(stringify_conditions(conditions)).pluck(:i).each do |item|
120
+ item.adjust_position(-1)
121
+ end
122
+ end
123
+
124
+ def less_than_me
125
+ { "i.#{position_key} <" => my_position.to_i }
126
+ end
127
+
128
+ def greater_than_me
129
+ { "i.#{position_key} >" => my_position.to_i }
130
+ end
131
+
132
+ def insert_at(position = 1)
133
+ insert_in_list_at(position)
134
+ end
135
+
136
+ def move_to(position = 1)
137
+ insert_in_list_at(position)
138
+ end
139
+
140
+ def move_below(object)
141
+ return if self == object
142
+ if object.my_position > my_position
143
+ move_to(object.my_position)
144
+ else
145
+ move_to(object.my_position + 1)
146
+ end
147
+ end
148
+
149
+ def move_above(object)
150
+ return if self == object
151
+ if object.my_position > my_position
152
+ move_to(object.my_position - 1)
153
+ else
154
+ move_to(object.my_position)
155
+ end
156
+ end
157
+
158
+ # Insert the item at the given position (defaults to the top position of 1).
159
+ def insert_in_list_at(position = 1)
160
+ insert_at_position(position)
161
+ end
162
+
163
+ # Swap positions with the next lower item, if one exists.
164
+ def move_lower
165
+ low_item = lower_item
166
+ return unless low_item
167
+
168
+ low_item.decrement_position
169
+ increment_position
170
+ end
171
+
172
+ # Swap positions with the next higher item, if one exists.
173
+ def move_higher
174
+ high_item = higher_item
175
+ return unless high_item
176
+
177
+ high_item.increment_position
178
+ decrement_position
179
+ end
180
+
181
+ # Move to the bottom of the list. If the item is already in the list, the items below it have their
182
+ # position adjusted accordingly.
183
+ def move_to_bottom
184
+ return unless in_list?
185
+
186
+ decrement_positions_on_lower_items
187
+ assume_bottom_position
188
+ end
189
+
190
+ # Move to the top of the list. If the item is already in the list, the items above it have their
191
+ # position adjusted accordingly.
192
+ def move_to_top
193
+ return unless in_list?
194
+
195
+ increment_positions_on_higher_items
196
+ assume_top_position
197
+ end
198
+
199
+ # Removes the item from the list.
200
+ def remove_from_list
201
+ return unless in_list?
202
+ decrement_positions_on_lower_items
203
+ set_my_position nil
204
+ end
205
+
206
+ # Increase the position of this item without adjusting the rest of the list.
207
+ def increment_position
208
+ return unless in_list?
209
+ # self_class_all_or_in_collection.where(:pos => my_position).
210
+ adjust_position!(1)
211
+ end
212
+
213
+ # Decrease the position of this item without adjusting the rest of the list.
214
+ def decrement_position
215
+ return unless in_list?
216
+
217
+ # self_class_all_or_in_collection.where(:pos => my_position).
218
+ adjust_position!(-1)
219
+ end
220
+
221
+ # Return +true+ if this object is the first in the list.
222
+ def first?
223
+ return false unless in_list?
224
+ my_position == 1
225
+ end
226
+
227
+ # Return +true+ if this object is the last in the list.
228
+ def last?
229
+ return false unless in_list?
230
+ bottom_pos = bottom_position_in_list
231
+ my_position == bottom_pos
232
+ end
233
+
234
+ # Return the next higher item in the list.
235
+ def higher_item
236
+ return nil unless in_list?
237
+ conditions = scope_condition.merge!(less_than_me)
238
+ order_by_position(conditions).last
239
+ end
240
+
241
+ # Return the next lower item in the list.
242
+ def lower_item
243
+ return nil unless in_list?
244
+
245
+ conditions = scope_condition.merge!(greater_than_me)
246
+ order_by_position(conditions).first
247
+ end
248
+
249
+ # Test if this record is in a list
250
+ def in_list?
251
+ !my_position.nil?
252
+ end
253
+
254
+ # sorts all items in the list
255
+ # if two items have same position, the one created more recently goes first
256
+ def sort
257
+ conditions = scope_condition
258
+ list_items = order_by_position(conditions, :created_at.desc).to_a
259
+
260
+ list_items.each_with_index do |list_item, index|
261
+ list_item.set_my_position index + 1
262
+ end
263
+ end
264
+
265
+ private
266
+
267
+ def self_class_all_or_in_collection
268
+ return in_collection.query_as(:i) if self.respond_to?(:in_collection)
269
+ self.class.all.query_as(:i)
270
+ end
271
+
272
+ def add_to_list_bottom
273
+ bottom_pos = bottom_position_in_list.to_i
274
+ set_my_position(bottom_pos + 1)
275
+ end
276
+
277
+ # Overwrite this method to define the scope of the list changes
278
+ def scope_condition
279
+ {}
280
+ end
281
+
282
+ # Returns the bottom position number in the list.
283
+ # bottom_position_in_list # => 2
284
+ def bottom_position_in_list(_except = nil)
285
+ item = bottom_item # (except)
286
+ item ? item.my_position : 0
287
+ end
288
+
289
+ # Returns the bottom item
290
+ def bottom_item(except = nil)
291
+ conditions = scope_condition
292
+ if except
293
+ conditions.merge!("i.#{position_key} <>" => except.my_position)
294
+ end
295
+
296
+ order_by_position(conditions).last
297
+ end
298
+
299
+ # Forces item to assume the bottom position in the list.
300
+ def assume_bottom_position
301
+ pos = bottom_position_in_list(self).to_i + 1
302
+ set_my_position(pos)
303
+ end
304
+
305
+ # Forces item to assume the top position in the list.
306
+ def assume_top_position
307
+ set_my_position(1)
308
+ end
309
+
310
+ # This has the effect of moving all the higher items up one.
311
+ def decrement_positions_on_higher_items(position)
312
+ conditions = scope_condition
313
+ conditions.merge!("i.#{position_key} <" => position)
314
+
315
+ decrease_all! self_class_all_or_in_collection.where(stringify_conditions(conditions))
316
+ end
317
+
318
+ # This has the effect of moving all the lower items up one.
319
+ def decrement_positions_on_lower_items(max_pos = nil)
320
+ return unless in_list?
321
+ conditions = scope_condition
322
+ conditions.merge!(greater_than_me)
323
+ conditions.merge!("i.#{position_key} <" => max_pos) if max_pos
324
+
325
+ decrease_all! self_class_all_or_in_collection.where(stringify_conditions(conditions))
326
+ end
327
+
328
+ # This has the effect of moving all the higher items down one.
329
+ def increment_positions_on_higher_items(min_pos = nil)
330
+ return unless in_list?
331
+ conditions = scope_condition
332
+ conditions.merge!(less_than_me)
333
+ conditions.merge!("i.#{position_key} >" => min_pos) if min_pos
334
+
335
+ increase_all! self_class_all_or_in_collection.where(stringify_conditions(conditions))
336
+ end
337
+
338
+ def adjust_all!(collection, number)
339
+ collection.pluck(:i).each do |item|
340
+ item.adjust_position! number
341
+ end
342
+ end
343
+
344
+ def increase_all!(collection)
345
+ adjust_all! collection, 1
346
+ end
347
+
348
+ def decrease_all!(collection)
349
+ adjust_all! collection, -1
350
+ end
351
+
352
+ # This has the effect of moving all the lower items down one.
353
+ def increment_positions_on_lower_items(position)
354
+ conditions = scope_condition
355
+ conditions.merge!("i.#{position_key} >=" => position)
356
+
357
+ increase_all! self_class_all_or_in_collection.where(stringify_conditions(conditions))
358
+ end
359
+
360
+ # Increments position (<tt>position_column</tt>) of all items in the list.
361
+ def increment_positions_on_all_items
362
+ conditions = scope_condition
363
+ increase_all! self_class_all_or_in_collection.where(stringify_conditions(conditions))
364
+ end
365
+
366
+ alias_method :add_to_list_top, :increment_positions_on_all_items
367
+
368
+ def insert_at_position(position)
369
+ position = [position, 1].max
370
+ remove_from_list
371
+ increment_positions_on_lower_items(position)
372
+ set_my_position(position)
373
+ end
374
+
375
+ def stringify_conditions(conditions)
376
+ return nil if conditions.empty?
377
+ conditions.reject { |_key, value| value.nil? }.map { |key, value| "#{key} #{value}" }.join(' and ')
378
+ end
379
+ end
380
+
381
+ module Triggers
382
+ def after_parentize
383
+ # should register on root element to be called when root is saved first time!?
384
+ end
385
+
386
+ def init_list_item
387
+ add_to_list_bottom unless in_list?
388
+ end
389
+ end
390
+
391
+ module Fields
392
+ def my_position
393
+ send position_column
394
+ end
395
+
396
+ def set_my_position(new_position)
397
+ return if new_position == my_position
398
+ if id
399
+ update_attributes! position_column => new_position
400
+ else
401
+ send "#{position_column}=", new_position
402
+ end
403
+ end
404
+
405
+ def ==(other)
406
+ return true if other.equal?(self)
407
+ return true if other.instance_of?(self.class) && other.respond_to?('id') && other.id == id
408
+ false
409
+ end
410
+
411
+ # Overwrites default comparer to return comparison index value based on defined position
412
+ def <=>(other)
413
+ my_position <=> other.my_position
414
+ end
415
+
416
+ def position_key
417
+ position_column.to_sym
418
+ end
419
+
420
+ def adjust_position!(number)
421
+ adjust_position(number)
422
+ save!
423
+ end
424
+
425
+ def adjust_position(number)
426
+ set_my_position(my_position + number)
427
+ end
428
+ end
429
+ end
430
+ end
431
+
432
+ class Array
433
+ def init_list!
434
+ each(&:init_list_item!)
435
+ end
436
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_list_neo4j
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stayman Hou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-26 00:00:00.000000000 Z
11
+ date: 2015-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: neo4j
@@ -148,7 +148,8 @@ extra_rdoc_files:
148
148
  files:
149
149
  - LICENSE.md
150
150
  - README.md
151
- - VERSION
151
+ - lib/acts_as_list_neo4j.rb
152
+ - lib/neo4j/acts_as_list.rb
152
153
  homepage: http://github.com/rails/acts_as_list
153
154
  licenses:
154
155
  - MIT
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.0.1