acts_as_list_neo4j 0.0.1 → 0.0.2

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