disposable 0.4.5 → 0.6.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +29 -0
  3. data/.gitignore +1 -0
  4. data/CHANGES.md +20 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile_builder_test.rb +6 -0
  7. data/README.md +4 -0
  8. data/Rakefile +8 -2
  9. data/disposable.gemspec +3 -6
  10. data/lib/disposable/twin/builder.rb +1 -0
  11. data/lib/disposable/twin/coercion.rb +7 -2
  12. data/lib/disposable/twin/default.rb +3 -3
  13. data/lib/disposable/twin/property/struct.rb +3 -1
  14. data/lib/disposable/twin/property/unnest.rb +4 -3
  15. data/lib/disposable/twin.rb +10 -4
  16. data/lib/disposable/version.rb +1 -1
  17. data/test/callback_group_test.rb +27 -27
  18. data/test/callbacks_test.rb +44 -44
  19. data/test/expose_test.rb +16 -16
  20. data/test/persisted_test.rb +30 -30
  21. data/test/rescheme_test.rb +22 -22
  22. data/test/skip_getter_test.rb +14 -14
  23. data/test/test_helper.rb +1 -1
  24. data/test/twin/builder_test.rb +7 -3
  25. data/test/twin/changed_test.rb +38 -38
  26. data/test/twin/coercion_test.rb +63 -26
  27. data/test/twin/collection_test.rb +46 -46
  28. data/test/twin/composition_test.rb +20 -20
  29. data/test/twin/default_test.rb +15 -15
  30. data/test/twin/expose_test.rb +15 -15
  31. data/test/twin/feature_test.rb +10 -10
  32. data/test/twin/from_collection_test.rb +4 -4
  33. data/test/twin/from_test.rb +3 -3
  34. data/test/twin/hash_test.rb +38 -38
  35. data/test/twin/inherit_test.rb +7 -7
  36. data/test/twin/inheritance_test.rb +6 -6
  37. data/test/twin/parent_test.rb +5 -5
  38. data/test/twin/property_processor_test.rb +3 -3
  39. data/test/twin/readable_test.rb +9 -9
  40. data/test/twin/save_test.rb +44 -44
  41. data/test/twin/setup_test.rb +25 -25
  42. data/test/twin/skip_unchanged_test.rb +6 -6
  43. data/test/twin/struct/coercion_test.rb +5 -5
  44. data/test/twin/struct_test.rb +41 -38
  45. data/test/twin/sync_test.rb +29 -29
  46. data/test/twin/twin_test.rb +24 -14
  47. data/test/twin/unnest_test.rb +7 -7
  48. data/test/twin/virtual_test.rb +3 -3
  49. data/test/twin/writeable_test.rb +8 -8
  50. metadata +14 -69
  51. data/.travis.yml +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a0b6cd70b82bc532b0a07ca0035dc1f1c6b112cb90fca7d244e1ac3468c327f
4
- data.tar.gz: 661653dde2ad0f4aca0107e84605e92764952023aae4c7b0d624cded6d7130ad
3
+ metadata.gz: ed1ac63bf425a0d6b32c6657b05391b2855c60f17313dbb5f0474db7031797d9
4
+ data.tar.gz: 768a3c634709bd4cdbab6fe6dc8c0a9203c9e98e41e66c923eba85eaf7f59c9f
5
5
  SHA512:
6
- metadata.gz: f382b96782f326b2b52a85cfdf340c99a29824af3aa7cccbf9129a146700b73b6b48137361e56a7b1b017b48236c6aef15029d98b78a35e192eafeb765caacb2
7
- data.tar.gz: b2712eab0e52144fbe418e2035dc39ccba6ce241304debaab9e04b4ee39f71dcc3eb95a77c0f1d2885538c38361f6efb896620c052e4bcb58f1529390b61eae8
6
+ metadata.gz: 15c35ed92488b90304978ff44c029b4058eee7de078cb62cda44b7f25a076dc9b04bddef1d98a3b071fa7f16c2c7aaff2b3c1d49c24f1c4549bdf8c21c12c1c0
7
+ data.tar.gz: 4d3818b186417407e00510ddc8704f9e5e79f50c922427f2e73ac2c82ffe24a4dcfd663e005bc9ea7acd288171000cacac78722c625c94190ec1f83e34958b90
@@ -0,0 +1,29 @@
1
+ name: CI
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ strategy:
6
+ fail-fast: false
7
+ matrix:
8
+ ruby: [2.5, 2.6]
9
+ active_record: [5.0, 5.2, 6.0]
10
+ dry_types: [0.13, 0.14, 0.15, 1.0, 1.1, 1.2]
11
+
12
+ include:
13
+ - ruby: 2.7
14
+ active_record: 6.1
15
+ dry_types: 1.5
16
+ # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0'
17
+ - ruby: '3.0'
18
+ active_record: 6.1
19
+ dry_types: 1.5
20
+
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v2
24
+ - uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: ${{ matrix.ruby }}
27
+ # bundler-cache: true # runs 'bundle install' and caches installed gems automatically
28
+ - run: ACTIVERECORD=${{ matrix.active_record}} DRY_TYPES=${{ matrix.dry_types }} bundle install
29
+ - run: ACTIVERECORD=${{ matrix.active_record}} DRY_TYPES=${{ matrix.dry_types }} bundle exec rake
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ test/tmp
15
15
  test/version_tmp
16
16
  tmp
17
17
  Gemfile*.lock
18
+ .rubocop*
data/CHANGES.md CHANGED
@@ -1,3 +1,23 @@
1
+ # 0.6.0
2
+
3
+ * Remove `uber` gem.
4
+ * Remove `declarative-builder` dependency and make it optional. Add `gem "declarative-builder"` to your `Gemfile` should you need this feature.
5
+
6
+ # 0.5.0
7
+
8
+ * Upgrade `representable` to replace `Declarative::Option` with `Representable::Option` in order to support ruby-3 style of keyword arguments.
9
+
10
+ # 0.4.7
11
+
12
+ * Deprecation warning for nilify options for dry-v >= 1.x
13
+ * Fix initializer struct when using `false` as value
14
+
15
+ # 0.4.6
16
+
17
+ * Remove deprecation warnings for newer versions of dry-types
18
+ * Fix sqlite3 version to 1.3.x to avoid issue with AR 5.0
19
+ * Raise an error if class is used as property name
20
+
1
21
  # 0.4.5
2
22
 
3
23
  * Use Gem::Version to detect version for dry-types
data/Gemfile CHANGED
@@ -7,4 +7,6 @@ gem "minitest-line"
7
7
  gem gem_name, dependency
8
8
  end
9
9
 
10
+ gem "sqlite3"#, ENV.fetch('ACTIVERECORD', '5.2').to_f >= 6 ? '~> 1.4' : '~> 1.3.0'
10
11
 
12
+ # gem "declarative-builder"
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+ gem "minitest-line"
4
+ gem "sqlite3"
5
+
6
+ gem "declarative-builder", "0.2.0"
data/README.md CHANGED
@@ -640,3 +640,7 @@ Note that this will internally add a `parent` property.
640
640
 
641
641
  * [Reform](https://github.com/apotonick/reform) forms are based on twins and add a little bit of form decoration on top. Every nested form is a twin.
642
642
  * [Trailblazer](https://github.com/apotonick/trailblazer) uses twins as decorators and callbacks in operations to structure business logic.
643
+
644
+ ## Development
645
+
646
+ * `rake test` runs all tests without `builder_test.rb`. For the latter, run `BUNDLE_GEMFILE=Gemfile_builder_test.rb bundle exec rake test_builder`
data/Rakefile CHANGED
@@ -4,6 +4,12 @@ require "rake/testtask"
4
4
  task :default => [:test]
5
5
  Rake::TestTask.new(:test) do |test|
6
6
  test.libs << 'test'
7
- test.test_files = FileList['test/**/*_test.rb']
7
+ test.test_files = FileList['test/**/*_test.rb'] - ["test/twin/builder_test.rb"]
8
8
  test.verbose = true
9
- end
9
+ end
10
+
11
+ Rake::TestTask.new(:test_builder) do |test|
12
+ test.libs << 'test'
13
+ test.test_files = FileList["test/twin/builder_test.rb"]
14
+ test.verbose = true
15
+ end
data/disposable.gemspec CHANGED
@@ -16,17 +16,14 @@ Gem::Specification.new do |spec|
16
16
  spec.test_files = spec.files.grep(%r{^(test)/})
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_dependency "uber", "< 0.2.0"
20
19
  spec.add_dependency "declarative", ">= 0.0.9", "< 1.0.0"
21
- spec.add_dependency "declarative-builder", "< 0.2.0"
22
- spec.add_dependency "declarative-option", "< 0.2.0"
23
- spec.add_dependency "representable", ">= 2.4.0", "<= 3.1.0"
20
+ # spec.add_dependency "declarative-builder" #, ">= 0.2.0"
21
+ spec.add_dependency "representable", ">= 3.1.1", "< 3.2.0"
24
22
 
25
- spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "bundler"#, "~> 1.3"
26
24
  spec.add_development_dependency "rake"
27
25
  spec.add_development_dependency "minitest"
28
26
  spec.add_development_dependency "activerecord"#, "4.2.5"
29
- spec.add_development_dependency "sqlite3"
30
27
  spec.add_development_dependency "dry-types"# "~> 0.6"
31
28
  # spec.add_development_dependency "database_cleaner"
32
29
  end
@@ -1,3 +1,4 @@
1
+ gem "declarative-builder", "0.2.0"
1
2
  require "declarative/builder"
2
3
 
3
4
  module Disposable
@@ -2,7 +2,9 @@ require "dry-types"
2
2
 
3
3
  module Disposable::Twin::Coercion
4
4
  module Types
5
- include Dry::Types.module
5
+ # NOTE: Use Dry.Types() instead. Beware, it exports strict types by default, for old behavior use Dry.Types(default: :nominal)
6
+ DRY_MODULE = Gem::Version.new(Dry::Types::VERSION) < Gem::Version.new("0.15.0") ? Dry::Types.module : Dry.Types()
7
+ include DRY_MODULE
6
8
  end
7
9
 
8
10
  DRY_TYPES_VERSION = Gem::Version.new(Dry::Types::VERSION)
@@ -16,7 +18,10 @@ module Disposable::Twin::Coercion
16
18
  end
17
19
 
18
20
  def coercing_setter!(name, type, nilify=false)
19
- type = type ? (DRY_TYPES_CONSTANT::Nil | type) : DRY_TYPES_CONSTANT::Nil if nilify
21
+ # TODO: remove nilily with next release (0.5) for new dry-type versions
22
+ type = type ? (DRY_TYPES_CONSTANT::Nil | type) : DRY_TYPES_CONSTANT::Nil if nilify
23
+
24
+ warn "DEPRECATION WARNING [Disposable]: nilify is deprecated and it will be removed with the next release" if nilify && DRY_TYPES_VERSION >= Gem::Version.new("1.0.0")
20
25
 
21
26
  mod = Module.new do
22
27
  define_method("#{name}=") do |value|
@@ -1,4 +1,4 @@
1
- require "declarative/option"
1
+ require "representable/option"
2
2
 
3
3
  # TODO: allow default: -> for hashes, etc.
4
4
  module Disposable::Twin::Default
@@ -12,13 +12,13 @@ module Disposable::Twin::Default
12
12
  # TODO: introduce Null object in Declarative::Definition#[].
13
13
  # dfn[:default].(self) # dfn#[] should return a Null object here if empty.
14
14
  return unless dfn[:default]
15
- dfn[:default].(self)
15
+ dfn[:default].(exec_context: self) # Representable::Option#call
16
16
  end
17
17
 
18
18
  module ClassMethods
19
19
  private
20
20
  def build_definition(name, options={}, &block)
21
- options = options.merge(default: Declarative::Option(options[:default], instance_exec: true)) if options.has_key?(:default)
21
+ options = options.merge(default: ::Representable::Option(options[:default])) if options.has_key?(:default)
22
22
  super
23
23
  end
24
24
  end
@@ -6,7 +6,9 @@ class Disposable::Twin
6
6
  module Struct
7
7
  def read_value_for(dfn, options)
8
8
  name = dfn[:name]
9
- @model[name.to_s] || @model[name.to_sym] # TODO: test sym vs. str.
9
+ # TODO: test sym vs. str.
10
+ return unless key_value = model.to_h.find { |k, _| k.to_sym == name.to_sym }
11
+ key_value.last
10
12
  end
11
13
 
12
14
  def sync_hash_representer # TODO: make this without representable, please.
@@ -1,10 +1,11 @@
1
- require "uber/delegates"
1
+ require "forwardable"
2
2
 
3
3
  module Disposable::Twin::Property
4
4
  module Unnest
5
+ extend Forwardable
5
6
  # TODO: test that nested properties options are "unnested", too, e.g. populator.
6
7
  def self.included(includer)
7
- includer.send(:include, Uber::Delegates)
8
+ includer.send(:include, Forwardable)
8
9
  end
9
10
 
10
11
  def unnest(name, options)
@@ -15,7 +16,7 @@ module Disposable::Twin::Property
15
16
  options = options.merge(virtual: true, _inherited: true, private_name: nil)
16
17
 
17
18
  property(name, options)
18
- delegates from, name, "#{name}="
19
+ def_delegators from, name, "#{name}="
19
20
  end
20
21
  end
21
22
  end
@@ -1,4 +1,3 @@
1
- require "uber/inheritable_attr"
2
1
  require "declarative/schema"
3
2
  require "representable/decorator"
4
3
 
@@ -9,6 +8,9 @@ require "representable/decorator"
9
8
 
10
9
  module Disposable
11
10
  class Twin
11
+ class InvalidPropertyNameError < StandardError; end
12
+ INVALID_PROPERTY_NAMES = %i[class].freeze
13
+
12
14
  extend Declarative::Schema
13
15
  def self.definition_class
14
16
  Definition
@@ -32,6 +34,10 @@ module Disposable
32
34
 
33
35
  # TODO: move to Declarative, as in Representable and Reform.
34
36
  def property(name, options={}, &block)
37
+ if INVALID_PROPERTY_NAMES.include?(name)
38
+ raise InvalidPropertyNameError.new("#{name} is used internally and cannot be used as property name")
39
+ end
40
+
35
41
  options[:private_name] ||= options.delete(:from) || name
36
42
  is_inherited = options.delete(:_inherited)
37
43
 
@@ -46,8 +52,8 @@ module Disposable
46
52
  end
47
53
  end
48
54
 
49
- def collection(name, options={}, &block)
50
- property(name, options.merge(collection: true), &block)
55
+ def collection(name, **options, &block)
56
+ property(name, **options.merge(collection: true), &block)
51
57
  end
52
58
 
53
59
  require "disposable/twin/property/unnest"
@@ -133,7 +139,7 @@ require "disposable/twin/definitions"
133
139
  require "disposable/twin/collection"
134
140
  require "disposable/twin/sync"
135
141
  require "disposable/twin/save"
136
- require "disposable/twin/builder"
142
+ # require "disposable/twin/builder"
137
143
  require "disposable/twin/changed"
138
144
  require "disposable/twin/property_processor"
139
145
  require "disposable/twin/persisted"
@@ -1,3 +1,3 @@
1
1
  module Disposable
2
- VERSION = "0.4.5"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -55,7 +55,7 @@ class CallbackGroupTest < MiniTest::Spec
55
55
  album = Album.new(songs: [Song.new(title: "Dead To Me"), Song.new(title: "Diesel Boy")])
56
56
  twin = AlbumTwin.new(album)
57
57
 
58
- Group.new(twin).().invocations.must_equal [
58
+ expect(Group.new(twin).().invocations).must_equal [
59
59
  [:on_change, :change!, []],
60
60
  [:on_add, :notify_album!, []],
61
61
  [:on_add, :reset_song!, []],
@@ -76,7 +76,7 @@ class CallbackGroupTest < MiniTest::Spec
76
76
 
77
77
  group = Group.new(twin).(content: content)
78
78
 
79
- group.invocations.must_equal [
79
+ expect(group.invocations).must_equal [
80
80
  [:on_change, :change!, [twin]],
81
81
  [:on_add, :notify_album!, [twin.songs[0], twin.songs[1]]],
82
82
  [:on_add, :reset_song!, [twin.songs[0], twin.songs[1]]],
@@ -85,8 +85,8 @@ class CallbackGroupTest < MiniTest::Spec
85
85
  [:on_update, :expire_cache!, []],
86
86
  ]
87
87
 
88
- content.must_equal "notify_album!notify_album!reset_song!reset_song!"
89
- group.output.must_equal "Album has changed!"
88
+ expect(content).must_equal "notify_album!notify_album!reset_song!reset_song!"
89
+ expect(group.output).must_equal "Album has changed!"
90
90
  end
91
91
 
92
92
 
@@ -129,7 +129,7 @@ class CallbackGroupTest < MiniTest::Spec
129
129
 
130
130
  # pp group.invocations
131
131
 
132
- group.invocations.must_equal [
132
+ expect(group.invocations).must_equal [
133
133
  [:on_change, :change!, [twin]],
134
134
  [:on_add, :notify_album!, [twin.songs[0]]],
135
135
  [:on_add, :reset_song!, [twin.songs[0]]],
@@ -138,7 +138,7 @@ class CallbackGroupTest < MiniTest::Spec
138
138
  [:on_update, :expire_cache!, []],
139
139
  ]
140
140
 
141
- content.must_equal "Op: changed! [CallbackGroupTest::Operation]Op: notify_album! [CallbackGroupTest::Operation]Op: reset_song! [CallbackGroupTest::Operation]"
141
+ expect(content).must_equal "Op: changed! [CallbackGroupTest::Operation]Op: notify_album! [CallbackGroupTest::Operation]Op: reset_song! [CallbackGroupTest::Operation]"
142
142
  end
143
143
  end
144
144
 
@@ -157,12 +157,12 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
157
157
  end
158
158
 
159
159
  it do
160
- Group.hooks.size.must_equal 4
161
- Group.hooks[0].to_s.must_equal "[:on_change, :change!, {}]"
160
+ expect(Group.hooks.size).must_equal 4
161
+ expect(Group.hooks[0].to_s).must_equal "[:on_change, :change!, {}]"
162
162
  # Group.hooks[1][1][:nested].hooks.to_s.must_equal "[[:on_add, [:notify_album!]],[:on_add, [:reset_song!]]]"
163
- Group.hooks[2].to_s.must_equal "[:on_change, :rehash_name!, {:property=>:title}]"
163
+ expect(Group.hooks[2].to_s).must_equal "[:on_change, :rehash_name!, {:property=>:title}]"
164
164
 
165
- Group.definitions.get(Group.hooks[3][1])[:nested].hooks.to_s.must_equal "[[:on_change, :sing!, {}]]"
165
+ expect(Group.definitions.get(Group.hooks[3][1])[:nested].hooks.to_s).must_equal "[[:on_change, :sing!, {}]]"
166
166
  end
167
167
 
168
168
  class EmptyGroup < Group
@@ -171,7 +171,7 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
171
171
 
172
172
 
173
173
  it do
174
- EmptyGroup.hooks.size.must_equal 4
174
+ expect(EmptyGroup.hooks.size).must_equal 4
175
175
  # TODO:
176
176
  end
177
177
 
@@ -183,10 +183,10 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
183
183
  end
184
184
 
185
185
  it do
186
- Group.hooks.size.must_equal 4
186
+ expect(Group.hooks.size).must_equal 4
187
187
  # pp EnhancedGroup.hooks
188
- EnhancedGroup.hooks.size.must_equal 6
189
- EnhancedGroup.definitions.get(EnhancedGroup.hooks[5][1])[:nested].hooks.to_s.must_equal "[[:on_add, :rewind!, {}]]"
188
+ expect(EnhancedGroup.hooks.size).must_equal 6
189
+ expect(EnhancedGroup.definitions.get(EnhancedGroup.hooks[5][1])[:nested].hooks.to_s).must_equal "[[:on_add, :rewind!, {}]]"
190
190
  end
191
191
 
192
192
  class EnhancedWithInheritGroup < EnhancedGroup
@@ -199,13 +199,13 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
199
199
  end
200
200
 
201
201
  it do
202
- Group.hooks.size.must_equal 4
203
- EnhancedGroup.hooks.size.must_equal 6
202
+ expect(Group.hooks.size).must_equal 4
203
+ expect(EnhancedGroup.hooks.size).must_equal 6
204
204
 
205
- EnhancedGroup.definitions.get(EnhancedGroup.hooks[5][1])[:nested].hooks.to_s.must_equal "[[:on_add, :rewind!, {}]]"
206
- EnhancedWithInheritGroup.hooks.size.must_equal 6
207
- EnhancedWithInheritGroup.definitions.get(EnhancedWithInheritGroup.hooks[1][1])[:nested].hooks.to_s.must_equal "[[:on_add, :rewind!, {}], [:on_add, :eat!, {}]]"
208
- EnhancedWithInheritGroup.definitions.get(EnhancedWithInheritGroup.hooks[3][1])[:nested].hooks.to_s.must_equal "[[:on_change, :sing!, {}], [:on_delete, :yell!, {}]]"
205
+ expect(EnhancedGroup.definitions.get(EnhancedGroup.hooks[5][1])[:nested].hooks.to_s).must_equal "[[:on_add, :rewind!, {}]]"
206
+ expect(EnhancedWithInheritGroup.hooks.size).must_equal 6
207
+ expect(EnhancedWithInheritGroup.definitions.get(EnhancedWithInheritGroup.hooks[1][1])[:nested].hooks.to_s).must_equal "[[:on_add, :rewind!, {}], [:on_add, :eat!, {}]]"
208
+ expect(EnhancedWithInheritGroup.definitions.get(EnhancedWithInheritGroup.hooks[3][1])[:nested].hooks.to_s).must_equal "[[:on_change, :sing!, {}], [:on_delete, :yell!, {}]]"
209
209
  end
210
210
 
211
211
  class RemovingInheritGroup < Group
@@ -226,10 +226,10 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
226
226
  # TODO: object_id tests for all nested representers.
227
227
 
228
228
  it do
229
- Group.hooks.size.must_equal 4
230
- RemovingInheritGroup.hooks.size.must_equal 3
231
- RemovingInheritGroup.definitions.get(RemovingInheritGroup.hooks[0][1])[:nested].hooks.to_s.must_equal "[[:on_add, :reset_song!, {}]]"
232
- RemovingInheritGroup.definitions.get(RemovingInheritGroup.hooks[2][1])[:nested].hooks.to_s.must_equal "[[:on_change, :sing!, {}]]"
229
+ expect(Group.hooks.size).must_equal 4
230
+ expect(RemovingInheritGroup.hooks.size).must_equal 3
231
+ expect(RemovingInheritGroup.definitions.get(RemovingInheritGroup.hooks[0][1])[:nested].hooks.to_s).must_equal "[[:on_add, :reset_song!, {}]]"
232
+ expect(RemovingInheritGroup.definitions.get(RemovingInheritGroup.hooks[2][1])[:nested].hooks.to_s).must_equal "[[:on_change, :sing!, {}]]"
233
233
  end
234
234
 
235
235
  # Group::clone
@@ -239,7 +239,7 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
239
239
  end
240
240
 
241
241
  it do
242
- Group.hooks.size.must_equal 4
243
- ClonedGroup.hooks.size.must_equal 3
242
+ expect(Group.hooks.size).must_equal 4
243
+ expect(ClonedGroup.hooks.size).must_equal 3
244
244
  end
245
- end
245
+ end