rom 0.5.0 → 0.6.0.beta1

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +19 -15
  3. data/.rubocop_todo.yml +28 -0
  4. data/.travis.yml +8 -1
  5. data/CHANGELOG.md +40 -0
  6. data/Gemfile +10 -2
  7. data/Guardfile +12 -10
  8. data/README.md +42 -43
  9. data/Rakefile +13 -23
  10. data/lib/rom.rb +19 -27
  11. data/lib/rom/command.rb +118 -0
  12. data/lib/rom/command_registry.rb +13 -27
  13. data/lib/rom/commands.rb +1 -59
  14. data/lib/rom/commands/abstract.rb +147 -0
  15. data/lib/rom/commands/composite.rb +47 -0
  16. data/lib/rom/commands/create.rb +2 -17
  17. data/lib/rom/commands/delete.rb +5 -25
  18. data/lib/rom/commands/result.rb +5 -5
  19. data/lib/rom/commands/update.rb +3 -27
  20. data/lib/rom/constants.rb +19 -0
  21. data/lib/rom/env.rb +85 -35
  22. data/lib/rom/global.rb +173 -42
  23. data/lib/rom/header.rb +5 -5
  24. data/lib/rom/header/attribute.rb +2 -2
  25. data/lib/rom/lint/enumerable_dataset.rb +52 -0
  26. data/lib/rom/lint/linter.rb +64 -0
  27. data/lib/rom/lint/repository.rb +78 -0
  28. data/lib/rom/lint/spec.rb +20 -0
  29. data/lib/rom/lint/test.rb +98 -0
  30. data/lib/rom/mapper.rb +32 -5
  31. data/lib/rom/mapper/attribute_dsl.rb +240 -0
  32. data/lib/rom/mapper/dsl.rb +100 -0
  33. data/lib/rom/mapper/model_dsl.rb +55 -0
  34. data/lib/rom/mapper_registry.rb +8 -1
  35. data/lib/rom/memory.rb +4 -0
  36. data/lib/rom/memory/commands.rb +46 -0
  37. data/lib/rom/memory/dataset.rb +72 -0
  38. data/lib/rom/memory/relation.rb +44 -0
  39. data/lib/rom/memory/repository.rb +62 -0
  40. data/lib/rom/memory/storage.rb +57 -0
  41. data/lib/rom/model_builder.rb +44 -5
  42. data/lib/rom/processor.rb +1 -1
  43. data/lib/rom/processor/transproc.rb +109 -16
  44. data/lib/rom/reader.rb +91 -39
  45. data/lib/rom/relation.rb +165 -26
  46. data/lib/rom/relation/composite.rb +132 -0
  47. data/lib/rom/relation/curried.rb +48 -0
  48. data/lib/rom/relation/lazy.rb +173 -0
  49. data/lib/rom/relation/loaded.rb +75 -0
  50. data/lib/rom/relation/registry_reader.rb +23 -0
  51. data/lib/rom/repository.rb +93 -34
  52. data/lib/rom/setup.rb +54 -98
  53. data/lib/rom/setup/finalize.rb +85 -76
  54. data/lib/rom/setup_dsl/command.rb +36 -0
  55. data/lib/rom/setup_dsl/command_dsl.rb +34 -0
  56. data/lib/rom/setup_dsl/mapper.rb +32 -0
  57. data/lib/rom/setup_dsl/mapper_dsl.rb +30 -0
  58. data/lib/rom/setup_dsl/relation.rb +21 -0
  59. data/lib/rom/setup_dsl/setup.rb +75 -0
  60. data/lib/rom/support/array_dataset.rb +38 -0
  61. data/lib/rom/support/class_builder.rb +44 -0
  62. data/lib/rom/support/class_macros.rb +56 -0
  63. data/lib/rom/support/data_proxy.rb +102 -0
  64. data/lib/rom/support/enumerable_dataset.rb +58 -0
  65. data/lib/rom/support/inflector.rb +73 -0
  66. data/lib/rom/support/options.rb +188 -0
  67. data/lib/rom/support/registry.rb +4 -8
  68. data/lib/rom/version.rb +1 -1
  69. data/rakelib/benchmark.rake +13 -0
  70. data/rakelib/mutant.rake +16 -0
  71. data/rakelib/rubocop.rake +18 -0
  72. data/rom.gemspec +4 -7
  73. data/spec/integration/commands/create_spec.rb +32 -24
  74. data/spec/integration/commands/delete_spec.rb +15 -7
  75. data/spec/integration/commands/update_spec.rb +13 -11
  76. data/spec/integration/mappers/deep_embedded_spec.rb +4 -11
  77. data/spec/integration/mappers/definition_dsl_spec.rb +31 -44
  78. data/spec/integration/mappers/embedded_spec.rb +9 -24
  79. data/spec/integration/mappers/group_spec.rb +22 -30
  80. data/spec/integration/mappers/prefixing_attributes_spec.rb +18 -23
  81. data/spec/integration/mappers/renaming_attributes_spec.rb +23 -38
  82. data/spec/integration/mappers/symbolizing_attributes_spec.rb +18 -24
  83. data/spec/integration/mappers/wrap_spec.rb +22 -30
  84. data/spec/integration/multi_repo_spec.rb +15 -37
  85. data/spec/integration/relations/reading_spec.rb +82 -14
  86. data/spec/integration/repositories/extending_relations_spec.rb +50 -0
  87. data/spec/integration/{adapters → repositories}/setting_logger_spec.rb +6 -5
  88. data/spec/integration/setup_spec.rb +59 -62
  89. data/spec/shared/enumerable_dataset.rb +49 -0
  90. data/spec/shared/one_behavior.rb +26 -0
  91. data/spec/shared/users_and_tasks.rb +11 -23
  92. data/spec/spec_helper.rb +16 -7
  93. data/spec/support/constant_leak_finder.rb +14 -0
  94. data/spec/test/memory_repository_lint_test.rb +27 -0
  95. data/spec/unit/rom/command_registry_spec.rb +44 -0
  96. data/spec/unit/rom/commands/result_spec.rb +14 -0
  97. data/spec/unit/rom/commands_spec.rb +174 -0
  98. data/spec/unit/rom/env_spec.rb +40 -7
  99. data/spec/unit/rom/global_spec.rb +14 -0
  100. data/spec/unit/rom/{mapper_builder_spec.rb → mapper/dsl_spec.rb} +52 -38
  101. data/spec/unit/rom/mapper_spec.rb +51 -10
  102. data/spec/unit/rom/{adapter/memory → memory}/dataset_spec.rb +6 -4
  103. data/spec/unit/rom/memory/repository_spec.rb +12 -0
  104. data/spec/unit/rom/memory/storage_spec.rb +45 -0
  105. data/spec/unit/rom/model_builder_spec.rb +4 -3
  106. data/spec/unit/rom/processor/transproc_spec.rb +1 -0
  107. data/spec/unit/rom/reader_spec.rb +97 -24
  108. data/spec/unit/rom/relation/composite_spec.rb +65 -0
  109. data/spec/unit/rom/relation/lazy_spec.rb +145 -0
  110. data/spec/unit/rom/relation/loaded_spec.rb +28 -0
  111. data/spec/unit/rom/relation_spec.rb +111 -6
  112. data/spec/unit/rom/repository_spec.rb +59 -9
  113. data/spec/unit/rom/setup_spec.rb +99 -11
  114. data/spec/unit/rom/support/array_dataset_spec.rb +59 -0
  115. data/spec/unit/rom/support/class_builder_spec.rb +42 -0
  116. data/spec/unit/rom/support/enumerable_dataset_spec.rb +17 -0
  117. data/spec/unit/rom/support/inflector_spec.rb +89 -0
  118. data/spec/unit/rom/support/options_spec.rb +119 -0
  119. metadata +74 -112
  120. data/lib/rom/adapter.rb +0 -191
  121. data/lib/rom/adapter/memory.rb +0 -32
  122. data/lib/rom/adapter/memory/commands.rb +0 -31
  123. data/lib/rom/adapter/memory/dataset.rb +0 -67
  124. data/lib/rom/adapter/memory/storage.rb +0 -26
  125. data/lib/rom/commands/with_options.rb +0 -18
  126. data/lib/rom/config.rb +0 -70
  127. data/lib/rom/mapper_builder.rb +0 -52
  128. data/lib/rom/mapper_builder/mapper_dsl.rb +0 -114
  129. data/lib/rom/mapper_builder/model_dsl.rb +0 -29
  130. data/lib/rom/reader_builder.rb +0 -48
  131. data/lib/rom/relation_builder.rb +0 -62
  132. data/lib/rom/setup/base_relation_dsl.rb +0 -46
  133. data/lib/rom/setup/command_dsl.rb +0 -46
  134. data/lib/rom/setup/mapper_dsl.rb +0 -19
  135. data/lib/rom/setup/relation_dsl.rb +0 -20
  136. data/lib/rom/setup/schema_dsl.rb +0 -33
  137. data/spec/integration/adapters/extending_relations_spec.rb +0 -41
  138. data/spec/integration/commands/try_spec.rb +0 -27
  139. data/spec/integration/schema_spec.rb +0 -77
  140. data/spec/unit/config_spec.rb +0 -60
  141. data/spec/unit/rom/adapter_spec.rb +0 -79
  142. data/spec/unit/rom_spec.rb +0 -14
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe ROM::Relation::Loaded do
4
+ include_context 'users and tasks'
5
+
6
+ subject(:users) { ROM::Relation::Loaded.new(rom.relations.users) }
7
+
8
+ before { setup.relation(:users) }
9
+
10
+ describe '#each' do
11
+ it 'yields tuples from relation' do
12
+ result = []
13
+ users.each { |tuple| result << tuple }
14
+ expect(result).to match_array([
15
+ { name: 'Jane', email: 'jane@doe.org' },
16
+ { name: 'Joe', email: 'joe@doe.org' }
17
+ ])
18
+ end
19
+
20
+ it 'returns enumerator when block is not provided' do
21
+ expect(users.each.to_a).to eql(users.collection.to_a)
22
+ end
23
+ end
24
+
25
+ it_behaves_like 'a relation that returns one tuple' do
26
+ let(:relation) { users }
27
+ end
28
+ end
@@ -1,17 +1,93 @@
1
1
  require 'spec_helper'
2
+ require 'rom/memory'
2
3
 
3
4
  describe ROM::Relation do
4
- subject(:relation) { ROM::Relation.new(dataset, dataset.header) }
5
+ subject(:relation) { Class.new(ROM::Relation).new(dataset) }
5
6
 
6
- let(:dataset) { ROM::Adapter::Memory::Dataset.new([jane, joe], [:id, :name]) }
7
+ let(:dataset) { ROM::Memory::Dataset.new([jane, joe]) }
7
8
 
8
9
  let(:jane) { { id: 1, name: 'Jane' } }
9
10
  let(:joe) { { id: 2, name: 'Joe' } }
10
11
 
11
- describe "#header" do
12
- it "return's duplicated and frozen dataset header" do
13
- expect(relation.header).to be_frozen
14
- expect(relation.header).not_to be(dataset.header)
12
+ describe '.[]' do
13
+ before do
14
+ module Test::TestAdapter
15
+ class Relation < ROM::Relation
16
+ def test_relation?
17
+ true
18
+ end
19
+ end
20
+ end
21
+
22
+ ROM.register_adapter(:test, Test::TestAdapter)
23
+ end
24
+
25
+ it 'returns relation subclass from the registered adapter' do
26
+ relation = ROM::Relation[:test].new([])
27
+
28
+ expect(relation).to be_test_relation
29
+ end
30
+ end
31
+
32
+ describe '#exposed_relations' do
33
+ it 'returns exposed relation name' do
34
+ relation_class = Class.new(ROM::Relation[:memory]) {
35
+ def foo
36
+ end
37
+
38
+ def bar
39
+ end
40
+ }
41
+
42
+ expect(relation_class.exposed_relations).to include(:foo, :bar)
43
+ end
44
+ end
45
+
46
+ describe '#name' do
47
+ before { ROM.setup(:memory) }
48
+
49
+ context 'missing dataset' do
50
+ context 'with Relation inside module' do
51
+ before do
52
+ module Test::Test
53
+ class SuperRelation < ROM::Relation[:memory]; end
54
+ end
55
+ end
56
+
57
+ it 'returns name based on module and class' do
58
+ relation = Test::Test::SuperRelation.new([])
59
+
60
+ expect(relation.name).to eq(:test_test_super_relation)
61
+ end
62
+ end
63
+
64
+ context 'with Relation without module' do
65
+ before do
66
+ class Test::SuperRelation < ROM::Relation[:memory]; end
67
+ end
68
+
69
+ it 'returns name based only on class' do
70
+ relation = Test::SuperRelation.new([])
71
+
72
+ expect(relation.name).to eq(:test_super_relation)
73
+ end
74
+ end
75
+ end
76
+
77
+ context 'manualy set dataset' do
78
+ before do
79
+ module Test::TestAdapter
80
+ class Relation < ROM::Relation[:memory]
81
+ dataset :foo_bar
82
+ end
83
+ end
84
+ end
85
+
86
+ it 'returns name based on dataset' do
87
+ relation = Test::TestAdapter::Relation.new([])
88
+
89
+ expect(relation.name).to eq(:foo_bar)
90
+ end
15
91
  end
16
92
  end
17
93
 
@@ -30,4 +106,33 @@ describe ROM::Relation do
30
106
  expect(relation.each).to be_instance_of(Enumerator)
31
107
  end
32
108
  end
109
+
110
+ describe ".register_as" do
111
+ before { ROM.setup(:memory) }
112
+
113
+ it "defaults to dataset with a generated class" do
114
+ rel = Class.new(ROM::Relation[:memory]) { dataset :users }
115
+ expect(rel.register_as).to eq(:users)
116
+ rel.register_as(:guests)
117
+ expect(rel.register_as).to eq(:guests)
118
+ end
119
+
120
+ it "defaults to dataset with a defined class that has dataset inferred" do
121
+ class Test::Users < ROM::Relation[:memory]; end
122
+ expect(Test::Users.register_as).to eq(:test_users)
123
+ end
124
+
125
+ it "defaults to dataset with a defined class that has dataset set manually" do
126
+ class Test::Users < ROM::Relation[:memory]
127
+ dataset :guests
128
+ end
129
+ expect(Test::Users.register_as).to eq(:guests)
130
+ end
131
+ end
132
+
133
+ describe "#to_a" do
134
+ it "materializes relation to an array" do
135
+ expect(relation.to_a).to eql([jane, joe])
136
+ end
137
+ end
33
138
  end
@@ -1,21 +1,71 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ROM::Repository do
4
- include_context 'users and tasks'
4
+ describe '.setup' do
5
+ it 'sets up a repository based on a type' do
6
+ repository_class = Class.new(ROM::Repository) do
7
+ attr_reader :args
5
8
 
6
- subject(:repository) { rom.memory }
9
+ def initialize(*args)
10
+ @args = args
11
+ end
12
+ end
7
13
 
8
- before { setup.relation(:users) }
14
+ allow(ROM::Repository).to receive(:class_from_symbol)
15
+ .with(:wormhole).and_return(repository_class)
9
16
 
10
- it 'exposes datasets on method-missing' do
11
- expect(repository.users).to be(rom.memory[:users])
17
+ args = %w(hello world)
18
+ repository = ROM::Repository.setup(:wormhole, *args)
19
+
20
+ expect(repository).to be_instance_of(repository_class)
21
+ expect(repository.args).to eq(args)
22
+ end
23
+
24
+ it 'raises an exception if the type is not supported' do
25
+ expect {
26
+ ROM::Repository.setup(:bogus, "memory://test")
27
+ }.to raise_error(ROM::AdapterLoadError, /bogus/)
28
+ end
29
+
30
+ it 'accepts a repository instance' do
31
+ repository = ROM::Repository.new
32
+ expect(ROM::Repository.setup(repository)).to be(repository)
33
+ end
34
+
35
+ it 'raises an exception if instance and arguments are passed' do
36
+ repository = ROM::Repository.new
37
+
38
+ expect { ROM::Repository.setup(repository, 'foo://bar') }.to raise_error(
39
+ ArgumentError,
40
+ "Can't accept arguments when passing an instance"
41
+ )
42
+ end
43
+
44
+ it 'raises an exception if a URI string is passed' do
45
+ expect { ROM::Repository.setup('memory://test') }.to raise_error(
46
+ ArgumentError,
47
+ /URIs without an explicit scheme are not supported anymore/
48
+ )
49
+ end
12
50
  end
13
51
 
14
- it 'responds to methods corresponding to dataset names' do
15
- expect(repository).to respond_to(:users)
52
+ describe '.class_from_symbol' do
53
+ it 'instantiates a repository based on type' do
54
+ klass = ROM::Repository.class_from_symbol(:memory)
55
+ expect(klass).to be(ROM::Memory::Repository)
56
+ end
57
+
58
+ it 'raises an exception if the type is not supported' do
59
+ expect { ROM::Repository.class_from_symbol(:bogus) }
60
+ .to raise_error(ROM::AdapterLoadError, /bogus/)
61
+ end
16
62
  end
17
63
 
18
- it 'raises exception when unknown dataset is referenced' do
19
- expect { repository.not_here }.to raise_error(NoMethodError)
64
+ describe '#disconnect' do
65
+ it 'does nothing' do
66
+ repository_class = Class.new(ROM::Repository)
67
+ repository = repository_class.new
68
+ expect(repository.disconnect).to be(nil)
69
+ end
20
70
  end
21
71
  end
@@ -2,23 +2,111 @@ require 'spec_helper'
2
2
 
3
3
  describe ROM::Setup do
4
4
  describe '#finalize' do
5
- context 'with an adapter that supports schema inferring' do
5
+ context 'with repository that supports schema inferring' do
6
6
  it 'builds relation from inferred schema' do
7
- adapter = double('adapter').as_null_object
8
- repo = double('repo', adapter: adapter).as_null_object
7
+ setup = ROM.setup(:memory)
8
+ repo = setup.default
9
9
  dataset = double('dataset')
10
10
 
11
- allow(repo).to receive(:schema).and_return([
12
- [:users, dataset, [:name, :email]]
13
- ])
11
+ allow(repo).to receive(:schema).and_return([:users])
12
+ allow(repo).to receive(:dataset).with(:users).and_return(dataset)
14
13
 
15
- setup = ROM::Setup.new(memory: repo)
16
- env = setup.finalize
14
+ rom = setup.finalize
17
15
 
18
- users = env.relations.users
16
+ expect(rom.relations.users.dataset).to be(dataset)
17
+ end
18
+
19
+ it 'skips inferring a relation when there is a defined one already' do
20
+ setup = ROM.setup(:memory)
21
+ repo = setup.default
22
+ dataset = double('dataset')
23
+
24
+ allow(repo).to receive(:schema).and_return([:test_users])
25
+ allow(repo).to receive(:dataset).with(:test_users).and_return(dataset)
26
+
27
+ class Test::Users < ROM::Relation[:memory]; end
28
+
29
+ expect { setup.finalize }.not_to raise_error
30
+
31
+ rom = setup.env
32
+
33
+ expect(rom.relations.test_users).to be_instance_of(Test::Users)
34
+ end
35
+
36
+ it 'can register multiple relations with same dataset' do
37
+ setup = ROM.setup(:memory)
38
+
39
+ Class.new(ROM::Relation[:memory]) {
40
+ dataset :fruits
41
+ register_as :apples
42
+
43
+ def apple?
44
+ true
45
+ end
46
+ }
47
+
48
+ Class.new(ROM::Relation[:memory]) {
49
+ dataset :fruits
50
+ register_as :oranges
51
+
52
+ def orange?
53
+ true
54
+ end
55
+ }
56
+
57
+ rom = setup.finalize
58
+
59
+ expect(rom.relations.apples).to be_apple
60
+ expect(rom.relations.oranges).to be_orange
61
+ expect(rom.relations.apples).to_not eq(rom.relations.oranges)
62
+ end
63
+
64
+ it "raises an error when registering relations with the same `register_as`" do
65
+ setup = ROM.setup(:memory)
66
+
67
+ Class.new(ROM::Relation[:memory]) {
68
+ dataset :guests
69
+ register_as :users
70
+ }
71
+
72
+ Class.new(ROM::Relation[:memory]) {
73
+ dataset :admins
74
+ register_as :users
75
+ }
76
+
77
+ expect { setup.finalize }.to raise_error(
78
+ ROM::RelationAlreadyDefinedError, /register_as :users/
79
+ )
80
+ end
81
+
82
+ it 'resets boot to nil' do
83
+ setup = ROM.setup(:memory)
84
+
85
+ allow(setup).to receive(:env).and_raise(StandardError)
86
+
87
+ expect { ROM.finalize }.to raise_error(StandardError)
88
+ expect(ROM.boot).to be(nil)
89
+ end
90
+ end
91
+
92
+ context 'empty setup' do
93
+ let(:setup) { ROM::Setup.new({}) }
94
+ let(:env) { setup.finalize }
95
+
96
+ it 'builds empty repositories' do
97
+ expect(env.repositories).to eql({})
98
+ end
99
+
100
+ it 'builds empty relations' do
101
+ expect(env.relations).to eql(ROM::RelationRegistry.new)
102
+ end
103
+
104
+ it 'builds empty readers' do
105
+ expect(env.readers).to eql(ROM::ReaderRegistry.new)
106
+ end
19
107
 
20
- expect(users.dataset).to be(dataset)
21
- expect(users.header).to eql([:name, :email])
108
+ it 'builds empty commands' do
109
+ expect(env.commands).to eql(ROM::Registry.new)
22
110
  end
23
111
  end
24
112
  end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ require 'rom/support/array_dataset'
4
+
5
+ describe ROM::ArrayDataset do
6
+ let(:klass) do
7
+ Class.new do
8
+ include ROM::ArrayDataset
9
+
10
+ def self.row_proc
11
+ Transproc(:symbolize_keys)
12
+ end
13
+ end
14
+ end
15
+
16
+ it_behaves_like 'an enumerable dataset' do
17
+ describe '#flatten' do
18
+ let(:data) { [[{ 'name' => 'Jane' }], [{ 'name' => 'Joe' }]] }
19
+
20
+ it 'returns a new dataset with flattened data' do
21
+ result = dataset.flatten
22
+
23
+ expect(result).to match_array([{ name: 'Jane' }, { name: 'Joe' }])
24
+ end
25
+ end
26
+
27
+ describe '#map!' do
28
+ context 'with a block' do
29
+ it 'returns a new dataset with mapped data' do
30
+ dataset.map! { |row| row.merge(age: 21) }
31
+
32
+ expect(dataset).to match_array([
33
+ { name: 'Jane', age: 21 }, { name: 'Joe', age: 21 }
34
+ ])
35
+ end
36
+ end
37
+
38
+ context 'without a block' do
39
+ it 'returns an enumerator' do
40
+ result = dataset.map!
41
+
42
+ expect(result).to be_instance_of(Enumerator)
43
+
44
+ expect(result).to match_array([
45
+ { name: 'Jane' }, { name: 'Joe' }
46
+ ])
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#values_at' do
52
+ it 'returns a new dataset with rows at given indices' do
53
+ result = dataset.values_at(1)
54
+
55
+ expect(result).to match_array([{ name: 'Joe' }])
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe ROM::ClassBuilder do
4
+ subject(:builder) { ROM::ClassBuilder.new(options) }
5
+
6
+ let(:klass) { builder.call }
7
+
8
+ describe '#call' do
9
+ let(:options) do
10
+ { name: 'Test', parent: parent }
11
+ end
12
+
13
+ let(:parent) { Class.new }
14
+
15
+ it 'returns a class constant' do
16
+ expect(klass).to be_instance_of(Class)
17
+ end
18
+
19
+ it 'sets class name based on provided :name option' do
20
+ expect(klass.name).to eql(options[:name])
21
+ end
22
+
23
+ it 'uses a parent class provided by :parent option' do
24
+ expect(klass).to be < parent
25
+ end
26
+
27
+ it 'defines to_s and inspect' do
28
+ expect(klass.to_s).to eql(options[:name])
29
+ expect(klass.inspect).to eql(options[:name])
30
+ end
31
+
32
+ it 'yields created class' do
33
+ klass = builder.call do |yielded_class|
34
+ yielded_class.class_eval do
35
+ def self.testing; end
36
+ end
37
+ end
38
+
39
+ expect(klass).to respond_to(:testing)
40
+ end
41
+ end
42
+ end