acts_as_list_with_sti_support 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_list_with_sti_support
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 0
10
- version: 1.0.0
9
+ - 1
10
+ version: 1.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Coroutine
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-10-10 00:00:00 -05:00
19
+ date: 2010-11-05 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
data/Rakefile CHANGED
@@ -1,28 +1,28 @@
1
- require 'rake'
2
- require 'rake/testtask'
3
- require 'rake/rdoctask'
4
- require 'jeweler'
1
+ require "rake"
2
+ require "rake/testtask"
3
+ require "rake/rdoctask"
4
+ require "jeweler"
5
5
 
6
6
 
7
- desc 'Default: run tests.'
7
+ desc "Default: run tests."
8
8
  task :default => [:test]
9
9
 
10
10
 
11
- desc 'Test the plugin.'
11
+ desc "Test the gem."
12
12
  Rake::TestTask.new(:test) do |t|
13
- t.libs << 'lib'
14
- t.pattern = 'test/**/*_test.rb'
15
- t.verbose = true
13
+ t.libs << ["lib", "test"]
14
+ t.pattern = "test/**/*_test.rb"
15
+ t.verbose = true
16
16
  end
17
17
 
18
18
 
19
- desc 'Generate documentation for the plugin.'
19
+ desc 'Generate documentation for the gem.'
20
20
  Rake::RDocTask.new(:rdoc) do |rdoc|
21
- rdoc.rdoc_dir = 'rdoc'
22
- rdoc.title = 'acts_as_list_with_sti_support'
23
- rdoc.options << '--line-numbers --inline-source'
24
- rdoc.rdoc_files.include('README')
25
- rdoc.rdoc_files.include('lib/**/*.rb')
21
+ rdoc.rdoc_dir = "rdoc"
22
+ rdoc.title = "acts_as_list_with_sti_support"
23
+ rdoc.options << "--line-numbers --inline-source"
24
+ rdoc.rdoc_files.include("README")
25
+ rdoc.rdoc_files.include("lib/**/*.rb")
26
26
  end
27
27
 
28
28
 
@@ -30,7 +30,7 @@ begin
30
30
  Jeweler::Tasks.new do |gemspec|
31
31
  gemspec.authors = ["Coroutine", "John Dugan"]
32
32
  gemspec.description = "This acts_as extension does everything acts_as_list does, but it also works in single table inheritance designs and accepts less brain-damaged scope syntax."
33
- gemspec.email = "jdugan@coroutine.com"
33
+ gemspec.email = "gem@coroutine.com"
34
34
  gemspec.homepage = "http://github.com/coroutine/acts_as_list_with_sti_support"
35
35
  gemspec.name = "acts_as_list_with_sti_support"
36
36
  gemspec.summary = "Gem version of acts_as_list_with_sti_support Rails plugin, a smarter version of acts_as_list."
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.2
@@ -5,13 +5,13 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{acts_as_list_with_sti_support}
8
- s.version = "1.0.1"
8
+ s.version = "1.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Coroutine", "John Dugan"]
12
- s.date = %q{2010-11-05}
12
+ s.date = %q{2010-12-13}
13
13
  s.description = %q{This acts_as extension does everything acts_as_list does, but it also works in single table inheritance designs and accepts less brain-damaged scope syntax.}
14
- s.email = %q{jdugan@coroutine.com}
14
+ s.email = %q{gem@coroutine.com}
15
15
  s.extra_rdoc_files = [
16
16
  "README.rdoc"
17
17
  ]
@@ -69,27 +69,29 @@ module Coroutine #:nodoc:
69
69
  validates_numericality_of column, :only_integer => true, :greater_than => 0, :allow_nil => true
70
70
 
71
71
 
72
- # Add callbacks
73
- begin
74
- before_validation :add_to_list_bottom, :on => :create # rails 3
75
- rescue
76
- before_validation_on_create :add_to_list_bottom # rails 2
77
- end
78
- before_destroy :remove_from_list
79
-
80
-
81
- # if no default scoping, order by position
82
- if self.default_scoping.empty?
83
- default_scope :order => column.to_s
84
- end
85
-
86
-
87
72
  # Include instance methods
88
73
  include Coroutine::ActsAsList::Base::InstanceMethods
89
74
 
75
+
76
+ # rails 3
77
+ if self.respond_to?(:arel_table)
78
+ before_validation :add_to_list_bottom, :if => :position_blank?, :on => :create
79
+ before_destroy :remove_from_list
80
+
81
+ # rails 2
82
+ else
83
+ before_validation_on_create :add_to_list_bottom, :if => :position_blank?
84
+ before_destroy :remove_from_list
85
+
86
+ if self.default_scoping.empty?
87
+ default_scope :order => column.to_s
88
+ end
89
+ end
90
+
90
91
  end
91
92
 
92
93
  end
94
+
93
95
  end
94
96
 
95
97
 
@@ -100,18 +102,21 @@ module Coroutine #:nodoc:
100
102
  #
101
103
  module InstanceMethods
102
104
 
103
- # Return the instance's class object
105
+ # This method returns the instance's class object
106
+ #
104
107
  def acts_as_list_class
105
108
  self.class
106
109
  end
107
110
 
108
- # Returns the column name that holds the position value.
111
+ # This method returns the column name that holds the position value.
112
+ #
109
113
  def position_column
110
114
  acts_as_list_column
111
115
  end
112
116
 
113
- # Returns the scope condition appropriate for the specified definition. (This could probably
114
- # be refactored for brevity.)
117
+ # This method returns the scope condition appropriate for the specified definition. (This
118
+ # could probably be refactored for brevity.)
119
+ #
115
120
  def scope_condition
116
121
  if acts_as_list_scope_condition.nil?
117
122
 
@@ -224,20 +229,21 @@ module Coroutine #:nodoc:
224
229
  def higher_item
225
230
  return nil unless in_list?
226
231
  conditions = "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}"
227
- begin
232
+ if self.rails_3?
228
233
  acts_as_list_class.where(conditions).first
229
- rescue
234
+ else
230
235
  acts_as_list_class.find(:first, :conditions => conditions)
231
236
  end
232
237
  end
233
238
 
234
- # Return the next lower item in the list.
239
+ # This method returns the next lower item in the list.
240
+ #
235
241
  def lower_item
236
242
  return nil unless in_list?
237
243
  conditions = "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}"
238
- begin
244
+ if self.rails_3?
239
245
  acts_as_list_class.where(conditions).first
240
- rescue
246
+ else
241
247
  acts_as_list_class.find(:first, :conditions => conditions)
242
248
  end
243
249
  end
@@ -247,40 +253,55 @@ module Coroutine #:nodoc:
247
253
  !send(position_column).nil?
248
254
  end
249
255
 
256
+ # This returns whether or not the position column is blank.
257
+ def position_blank?
258
+ return self.send(position_column).blank?
259
+ end
260
+
261
+ # This method indicates whether or not the gem is being used within the
262
+ # rails 3 environment.
263
+ def rails_3?
264
+ return acts_as_list_class.respond_to?(:arel_table)
265
+ end
266
+
267
+
268
+
250
269
  private
270
+
271
+ # This method adds the new item to the top of the list.
251
272
  def add_to_list_top
252
273
  increment_positions_on_all_items
253
274
  end
254
275
 
276
+ # This method adds the new item to the bottom of the list.
255
277
  def add_to_list_bottom
256
278
  self[position_column] = bottom_position_in_list.to_i + 1
257
279
  end
258
280
 
259
- # Returns the bottom position number in the list.
260
- # bottom_position_in_list # => 2
281
+ # This method returns the bottom position number in the list.
261
282
  def bottom_position_in_list(except = nil)
262
283
  item = bottom_item(except)
263
284
  item ? item.send(position_column) : 0
264
285
  end
265
286
 
266
- # Returns the bottom item
287
+ # This method returns the bottom item.
267
288
  def bottom_item(except = nil)
268
289
  conditions = scope_condition
269
- conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except
290
+ conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" unless except.blank?
270
291
  order_by = "#{position_column} DESC"
271
- begin
272
- acts_as_list_class.where(conditions).first.order(order_by)
273
- rescue
292
+ if self.rails_3?
293
+ acts_as_list_class.where(conditions).order(order_by).first
294
+ else
274
295
  acts_as_list_class.find(:first, :conditions => conditions, :order => order_by)
275
296
  end
276
297
  end
277
298
 
278
- # Forces item to assume the bottom position in the list.
299
+ # This method forces item to assume the bottom position in the list.
279
300
  def assume_bottom_position
280
301
  update_attribute(position_column, bottom_position_in_list(self).to_i + 1)
281
302
  end
282
303
 
283
- # Forces item to assume the top position in the list.
304
+ # This method forces item to assume the top position in the list.
284
305
  def assume_top_position
285
306
  update_attribute(position_column, 1)
286
307
  end
@@ -322,6 +343,7 @@ module Coroutine #:nodoc:
322
343
  )
323
344
  end
324
345
 
346
+ # This adds the item at the specified position value.
325
347
  def insert_at_position(position)
326
348
  remove_from_list
327
349
  increment_positions_on_lower_items(position)
@@ -3,7 +3,7 @@
3
3
  #---------------------------------------------------------
4
4
 
5
5
  # all generic requirements are in the helper
6
- require "test/test_helper"
6
+ require "test_helper"
7
7
 
8
8
 
9
9
 
@@ -99,9 +99,9 @@ end
99
99
 
100
100
  # Contacts
101
101
  class Contact < ActiveRecord::Base
102
- has_many :emails
103
- has_many :phones
104
- has_many :websites
102
+ has_many :emails, :order => "pos"
103
+ has_many :phones, :order => "position"
104
+ has_many :websites, :order => "position"
105
105
 
106
106
  def email_ids
107
107
  self.emails(true).map(&:id)
@@ -276,6 +276,39 @@ class ActsAsListTest < ActiveSupport::TestCase
276
276
 
277
277
 
278
278
 
279
+ #---------------------------------------------
280
+ # test default ordering
281
+ #---------------------------------------------
282
+
283
+ def test_default_ordering
284
+
285
+ # standard model
286
+ assert_equal 4, Contact.first.phones.size
287
+
288
+ p3 = Phone.create!({ :contact_id => Contact.last.id, :number => "901.555.7777" })
289
+ assert_equal 3, p3.position
290
+
291
+ p5 = Phone.create!({ :contact_id => Contact.last.id, :number => "901.555.9999", :position => 5 })
292
+ p4 = Phone.create!({ :contact_id => Contact.last.id, :number => "901.555.8888", :position => 4 })
293
+ assert_equal 4, p4.position
294
+ assert_equal 5, p5.position
295
+
296
+
297
+ # sti model
298
+ assert_equal 0, TaxFrequency.count
299
+
300
+ t1 = TaxFrequency.create!({ :label => "Monthly" })
301
+ assert_equal 1, t1.position
302
+
303
+ t3 = TaxFrequency.create!({ :label => "Yearly", :position => 3 })
304
+ t2 = TaxFrequency.create!({ :label => "Quarterly", :position => 2 })
305
+ assert_equal 2, t2.position
306
+ assert_equal 3, t3.position
307
+
308
+ end
309
+
310
+
311
+
279
312
  #---------------------------------------------
280
313
  # test ordering methods
281
314
  #---------------------------------------------
@@ -285,51 +318,51 @@ class ActsAsListTest < ActiveSupport::TestCase
285
318
  # standard model
286
319
  contact = Contact.first
287
320
  assert_equal [1, 2, 3, 4], contact.phone_ids
288
-
321
+
289
322
  Phone.find(2).move_lower
290
323
  assert_equal [1, 3, 2, 4], contact.phone_ids
291
-
324
+
292
325
  Phone.find(2).move_higher
293
326
  assert_equal [1, 2, 3, 4], contact.phone_ids
294
-
327
+
295
328
  Phone.find(1).move_to_bottom
296
329
  assert_equal [2, 3, 4, 1], contact.phone_ids
297
-
330
+
298
331
  Phone.find(1).move_to_top
299
332
  assert_equal [1, 2, 3, 4], contact.phone_ids
300
-
333
+
301
334
  Phone.find(2).move_to_bottom
302
335
  assert_equal [1, 3, 4, 2], contact.phone_ids
303
-
336
+
304
337
  Phone.find(4).move_to_top
305
338
  assert_equal [4, 1, 3, 2], contact.phone_ids
306
339
 
307
340
 
308
341
  # sti model
309
342
  assert_equal [1, 2, 3, 4], BillingFrequency.ids
310
-
343
+
311
344
  BillingFrequency.find(2).move_lower
312
345
  assert_equal [1, 3, 2, 4], BillingFrequency.ids
313
-
346
+
314
347
  BillingFrequency.find(2).move_higher
315
348
  assert_equal [1, 2, 3, 4], BillingFrequency.ids
316
-
349
+
317
350
  BillingFrequency.find(1).move_to_bottom
318
351
  assert_equal [2, 3, 4, 1], BillingFrequency.ids
319
-
352
+
320
353
  BillingFrequency.find(1).move_to_top
321
354
  assert_equal [1, 2, 3, 4], BillingFrequency.ids
322
-
355
+
323
356
  BillingFrequency.find(2).move_to_bottom
324
357
  assert_equal [1, 3, 4, 2], BillingFrequency.ids
325
-
358
+
326
359
  BillingFrequency.find(4).move_to_top
327
360
  assert_equal [4, 1, 3, 2], BillingFrequency.ids
328
361
  end
329
-
330
-
362
+
363
+
331
364
  def test_move_to_bottom_with_next_to_last_item
332
-
365
+
333
366
  # standard model
334
367
  contact = Contact.first
335
368
  assert_equal [1, 2, 3, 4], contact.phone_ids
@@ -360,8 +393,8 @@ class ActsAsListTest < ActiveSupport::TestCase
360
393
  assert_equal BillingFrequency.find(3), BillingFrequency.find(4).higher_item
361
394
  assert_nil BillingFrequency.find(4).lower_item
362
395
  end
363
-
364
-
396
+
397
+
365
398
  def test_insert
366
399
 
367
400
  # standard model
@@ -369,17 +402,17 @@ class ActsAsListTest < ActiveSupport::TestCase
369
402
  assert_equal 1, new.position
370
403
  assert new.first?
371
404
  assert new.last?
372
-
405
+
373
406
  new = Phone.create(:contact_id => 3, :number => "901.555.8888")
374
407
  assert_equal 2, new.position
375
408
  assert !new.first?
376
409
  assert new.last?
377
-
410
+
378
411
  new = Phone.create(:contact_id => 3, :number => "901.555.9999")
379
412
  assert_equal 3, new.position
380
413
  assert !new.first?
381
414
  assert new.last?
382
-
415
+
383
416
  new = Phone.create(:contact_id => 4, :number => "901.555.0000")
384
417
  assert_equal 1, new.position
385
418
  assert new.first?
@@ -391,17 +424,17 @@ class ActsAsListTest < ActiveSupport::TestCase
391
424
  assert_equal 1, new.position
392
425
  assert new.first?
393
426
  assert new.last?
394
-
427
+
395
428
  new = TaxFrequency.create(:label => "Quarterly")
396
429
  assert_equal 2, new.position
397
430
  assert !new.first?
398
431
  assert new.last?
399
-
432
+
400
433
  new = TaxFrequency.create(:label => "Yearly")
401
434
  assert_equal 3, new.position
402
435
  assert !new.first?
403
436
  assert new.last?
404
-
437
+
405
438
  new = PaymentFrequency.create(:label => "Monthly")
406
439
  assert_equal 1, new.position
407
440
  assert new.first?
@@ -414,34 +447,34 @@ class ActsAsListTest < ActiveSupport::TestCase
414
447
  # stadard model
415
448
  new = Phone.create(:contact_id => 3, :number => "615.555.1111")
416
449
  assert_equal 1, new.position
417
-
450
+
418
451
  new = Phone.create(:contact_id => 3, :number => "615.555.2222")
419
452
  assert_equal 2, new.position
420
-
453
+
421
454
  new = Phone.create(:contact_id => 3, :number => "615.555.3333")
422
455
  assert_equal 3, new.position
423
-
456
+
424
457
  new4 = Phone.create(:contact_id => 3, :number => "615.555.4444")
425
458
  assert_equal 4, new4.position
426
-
459
+
427
460
  new4.insert_at(3)
428
461
  assert_equal 3, new4.position
429
-
462
+
430
463
  new.reload
431
464
  assert_equal 4, new.position
432
-
465
+
433
466
  new.insert_at(2)
434
467
  assert_equal 2, new.position
435
-
468
+
436
469
  new4.reload
437
470
  assert_equal 4, new4.position
438
-
471
+
439
472
  new5 = Phone.create(:contact_id => 3, :number => "615.555.5555")
440
473
  assert_equal 5, new5.position
441
-
474
+
442
475
  new5.insert_at(1)
443
476
  assert_equal 1, new5.position
444
-
477
+
445
478
  new4.reload
446
479
  assert_equal 5, new4.position
447
480
 
@@ -449,45 +482,45 @@ class ActsAsListTest < ActiveSupport::TestCase
449
482
  # sti model
450
483
  new = TaxFrequency.create(:label => "Weekly")
451
484
  assert_equal 1, new.position
452
-
485
+
453
486
  new = TaxFrequency.create(:label => "Monthly")
454
487
  assert_equal 2, new.position
455
-
488
+
456
489
  new = TaxFrequency.create(:label => "Quarterly")
457
490
  assert_equal 3, new.position
458
-
491
+
459
492
  new4 = TaxFrequency.create(:label => "Yearly")
460
493
  assert_equal 4, new4.position
461
-
494
+
462
495
  new4.insert_at(3)
463
496
  assert_equal 3, new4.position
464
-
497
+
465
498
  new.reload
466
499
  assert_equal 4, new.position
467
-
500
+
468
501
  new.insert_at(2)
469
502
  assert_equal 2, new.position
470
-
503
+
471
504
  new4.reload
472
505
  assert_equal 4, new4.position
473
-
506
+
474
507
  new5 = TaxFrequency.create(:label => "Daily")
475
508
  assert_equal 5, new5.position
476
-
509
+
477
510
  new5.insert_at(1)
478
511
  assert_equal 1, new5.position
479
-
512
+
480
513
  new4.reload
481
514
  assert_equal 5, new4.position
482
515
  end
483
-
484
-
516
+
517
+
485
518
  def test_delete_middle
486
519
 
487
520
  # standard model
488
521
  contact = Contact.first
489
522
  assert_equal [1, 2, 3, 4], contact.phone_ids
490
-
523
+
491
524
  Phone.find(2).destroy
492
525
  assert_equal [1, 3, 4], contact.phone_ids
493
526
 
@@ -498,8 +531,8 @@ class ActsAsListTest < ActiveSupport::TestCase
498
531
  Phone.find(1).destroy
499
532
  assert_equal [3, 4], contact.phone_ids
500
533
 
501
- # assert_equal 1, Phone.find(3).position
502
- # assert_equal 2, Phone.find(4).position
534
+ assert_equal 1, Phone.find(3).position
535
+ assert_equal 2, Phone.find(4).position
503
536
 
504
537
 
505
538
  # sti model
@@ -518,8 +551,8 @@ class ActsAsListTest < ActiveSupport::TestCase
518
551
  assert_equal 1, BillingFrequency.find(3).position
519
552
  assert_equal 2, BillingFrequency.find(4).position
520
553
  end
521
-
522
-
554
+
555
+
523
556
  def test_remove_from_list_should_then_fail_in_list?
524
557
 
525
558
  # standard model
@@ -535,7 +568,7 @@ class ActsAsListTest < ActiveSupport::TestCase
535
568
  BillingFrequency.find(1).remove_from_list
536
569
  assert_equal false, BillingFrequency.find(1).in_list?
537
570
  end
538
-
571
+
539
572
 
540
573
  def test_remove_from_list_should_set_position_to_nil
541
574
 
@@ -563,8 +596,8 @@ class ActsAsListTest < ActiveSupport::TestCase
563
596
  assert_equal 2, BillingFrequency.find(3).position
564
597
  assert_equal 3, BillingFrequency.find(4).position
565
598
  end
566
-
567
-
599
+
600
+
568
601
  def test_remove_before_destroy_does_not_shift_lower_items_twice
569
602
 
570
603
  # standard model
@@ -13,13 +13,33 @@ require "#{File.dirname(__FILE__)}/../init"
13
13
  # Define global methods
14
14
  #----------------------------------------------------------
15
15
 
16
+ def puts_debug(*args)
17
+ objs = args.flatten
18
+
19
+ puts ""
20
+ puts "======================================"
21
+ objs.each_with_index do |obj, index|
22
+ puts "--------------------------------------" unless index == 0
23
+ puts "DEBUG: #{obj.inspect}"
24
+ end
25
+ puts "======================================"
26
+ puts ""
27
+ end
28
+
29
+
30
+
31
+ #----------------------------------------------------------
32
+ # Extend test class
33
+ #----------------------------------------------------------
34
+
16
35
  class ActiveSupport::TestCase
17
36
 
18
37
  # This method allows us to use a convenient notation for testing
19
38
  # model validations.
39
+ #
20
40
  def assert_not_valid(object, msg="Object is valid when it should be invalid")
21
41
  assert(!object.valid?, msg)
22
42
  end
23
43
  alias :assert_invalid :assert_not_valid
24
-
44
+
25
45
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_list_with_sti_support
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
5
4
  prerelease: false
6
5
  segments:
7
6
  - 1
8
7
  - 0
9
- - 1
10
- version: 1.0.1
8
+ - 2
9
+ version: 1.0.2
11
10
  platform: ruby
12
11
  authors:
13
12
  - Coroutine
@@ -16,7 +15,7 @@ autorequire:
16
15
  bindir: bin
17
16
  cert_chain: []
18
17
 
19
- date: 2010-11-05 00:00:00 -05:00
18
+ date: 2010-12-13 00:00:00 -06:00
20
19
  default_executable:
21
20
  dependencies:
22
21
  - !ruby/object:Gem::Dependency
@@ -27,7 +26,6 @@ dependencies:
27
26
  requirements:
28
27
  - - ">="
29
28
  - !ruby/object:Gem::Version
30
- hash: 11
31
29
  segments:
32
30
  - 2
33
31
  - 3
@@ -43,7 +41,6 @@ dependencies:
43
41
  requirements:
44
42
  - - ">="
45
43
  - !ruby/object:Gem::Version
46
- hash: 11
47
44
  segments:
48
45
  - 2
49
46
  - 3
@@ -52,7 +49,7 @@ dependencies:
52
49
  type: :development
53
50
  version_requirements: *id002
54
51
  description: This acts_as extension does everything acts_as_list does, but it also works in single table inheritance designs and accepts less brain-damaged scope syntax.
55
- email: jdugan@coroutine.com
52
+ email: gem@coroutine.com
56
53
  executables: []
57
54
 
58
55
  extensions: []
@@ -87,7 +84,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
87
84
  requirements:
88
85
  - - ">="
89
86
  - !ruby/object:Gem::Version
90
- hash: 3
91
87
  segments:
92
88
  - 0
93
89
  version: "0"
@@ -96,7 +92,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
92
  requirements:
97
93
  - - ">="
98
94
  - !ruby/object:Gem::Version
99
- hash: 3
100
95
  segments:
101
96
  - 0
102
97
  version: "0"