stubberry 0.1.0 → 0.1.1

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
  SHA256:
3
- metadata.gz: 76a44be83df94f95993dad5da5a540ec3b5f7d6a3334b45fb9f19d64f11445bd
4
- data.tar.gz: 7644abf117453f0635e8f14899d400f515c3a3ed763a3fff3737aa3ebb24408a
3
+ metadata.gz: 84ce1669272b052fded99ad9ba06ff354ef8dec1891a47e288140b554f159bdc
4
+ data.tar.gz: e113462e1d879af411a08b81dac5f77ce9d5f9341c700b6b4a2559c72dae5368
5
5
  SHA512:
6
- metadata.gz: 7c205abde785d061fab126fe889aa87cf611dc9851697aca91ba3e1ddd3c1d2dcac7ce2e1226f4aa6298027ba521913177547db185382ff77b9d85566e88d003
7
- data.tar.gz: '0579be30cd4c3e44e492f3262417105feeff44fdf48cbaa0ebfffd3b56e8337571051bc6eb50f8dbdf53e433e82e8c0a33bf7fc48ec3a6d38a48b071a320fdb2'
6
+ metadata.gz: dd67bcee9b9ef05fe6fc89c5223fa59560ea2229b3835517463e88543256623fc2568277732e38317e95ee8d2573c4d1da4ad72136da2cd0ba639071a9ddd6cc
7
+ data.tar.gz: 7db15cd29b4d85cbc03a20a701aa693c57c5f11ad8c2d81c1298c0753b84282a639f279f0fa3753e295d40b9a70539dc2631676654d36f34c54e9afe7531a4af
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /.idea/
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ # 0.1.1
2
+ * initial gem release
3
+ * Stubberry::Object module with stub_must, stub_must_not, stub_must_all, stub_if_* methods
4
+ * Stubberry::ActiveRecord easy id based stubbing active record objects inside some actions flow
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Stubberry
2
+ Pay attention it has 2Bs and 2Rs in naming :)
2
3
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/stubberry`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
4
+ This gem is planned to be a ultimate sweet collection of stubbing methods for all kinds of testing.
5
+ Feel free to provide any enrichment suggestions.
6
6
 
7
7
  ## Installation
8
8
 
@@ -22,7 +22,95 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- TODO: Write usage instructions here
25
+ Version 0.1 of this gem has two cool sets of stub methods Stubberry::Object and Stubberry::ActiveRecord
26
+
27
+
28
+ ### Stubberry::Object
29
+
30
+ Set of stubbing methods added to an Object class hence available for any class or its instances.
31
+
32
+ ```ruby
33
+
34
+ # a copy/paste of an Objects stub method enriched with
35
+ # raise error functionality whenever stubbed method wasn't called
36
+ # stub_must( name, val_or_callable, *block_args )
37
+
38
+ test 'check call params with a call must happened' do
39
+ class_or_obj.stub_must(:run, -> ( param ) {
40
+ # Now you can be sure: either you have an expected param, OR
41
+ # if call didn't happened you will see a StandardError raised
42
+ assert_equal( param, 1 )
43
+ } ) { class_or_obj.run(1) }
44
+ end
45
+
46
+ ```
47
+
48
+ Rem: I know about Mock object, but I don't like it. You may consider approach with mock/verify better or more object oriented e.t.c.
49
+ But I do like an error to be aligned to the check, running mock.verify some place after check did happened, feels unnatural and uncomfortable to me
50
+
51
+ ```ruby
52
+ # the reverse method of stub_must -- will raise an issue whenever method
53
+ # was called inside a stubbing block, ensures that flow didn't reach given method
54
+ # stub_must_not( name, message = nil )
55
+ test 'call must not happened' do
56
+ class_or_obj.stub_must_not(:run) { class_or_obj.call(1) }
57
+ end
58
+
59
+ # just for fun multiple stub_must in one call
60
+ # stub_must_all( name_to_var_or_callable, &block )
61
+ test 'all calls should happened' do
62
+ class_or_obj.stub_must_all(
63
+ run: true,
64
+ call: -> (param) { assert_equal(param, 1) }
65
+ ) do
66
+ class_or_obj.call(1)
67
+ class_or_obj.run(args)
68
+ end
69
+ end
70
+
71
+ # stub only if respond_to otherwise just execute block.
72
+ # It's a really rare case, I used only once for incompatible gems versions test
73
+ #
74
+ # stub_if_def(name, val_or_callable, *block_args, &block)
75
+ test 'all calls should happened' do
76
+ class_or_obj.stub_if_def( :not_def, -> (param) { assert_equal(param, :param) } ) do
77
+ # when there is nothing to stub, just yield
78
+ :just_yield_this_without_stubbing
79
+ end
80
+ end
81
+
82
+ # stub_must_if_def(name, val_or_callable, *block_args, &block)
83
+ # same as above but with stub_must under the hood
84
+ ```
85
+
86
+ ### Stubberry::ActiveRecord
87
+
88
+ Easy stubbing for ActiveRecord objects, you just need the id and Stubberry will do the rest.
89
+ The cool stuff about these stubbing methods is an independence from the way object retrieved.
90
+ You can get object via find, where or any relation, it doesn't matter.
91
+ Stubbing is based on after_find callback, so whenever object instantiated
92
+ it will be properly stubbed.
93
+
94
+ ```ruby
95
+ # you can stub active record object attributes with stub_orm_attr
96
+
97
+ test 'object attributes will be stubbed in relations' do
98
+ Comment.stub_orm_attr(1, {body: 'ola!'} ) do
99
+ assert_equal( 'ola!', User.first.comments.where(id: 1).take.body )
100
+ assert_equal( 'ola!', Comment.find(1).body )
101
+ end
102
+ end
103
+
104
+ # you can stub active record object method with stub_orm_method
105
+ test 'object with a given id got method stubbed' do
106
+ Comment.stub_orm_method(1, join: -> ( other ) {
107
+ assert_equal( other.id, 2 )
108
+ } ) do
109
+ User.first.comments.where(id: 1).each{ _1.join( Comment.find(2) ) }
110
+ end
111
+ end
112
+ ```
113
+
26
114
 
27
115
  ## Development
28
116
 
@@ -32,7 +120,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
120
 
33
121
  ## Contributing
34
122
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/stubberry. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/stubberry/blob/master/CODE_OF_CONDUCT.md).
123
+ Bug reports and pull requests are welcome on GitHub at https://github.com/alekseyl/stubberry. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/stubberry/blob/master/CODE_OF_CONDUCT.md).
36
124
 
37
125
 
38
126
  ## License
@@ -0,0 +1,84 @@
1
+ # this module provide two methods for active record classes
2
+ # to easily stub any record attributes and methods disregarding the way
3
+ # record was obtained inside the yielding block, you just need an id.
4
+ #
5
+ # i.e. alternative way of dealing with any record with id could be stub of
6
+ # the specific method like where or find with a given set of params e.t.c.
7
+ # that's a very error prone approach, with stub_orm_* methods we
8
+ # do not care about the way object was obtained as long as after_find
9
+ # callback was executed
10
+ module Stubberry::ActiveRecord
11
+ extend ActiveSupport::Concern
12
+
13
+ # for any active record object for classes included Stubberry::ActiveRecord
14
+ # we adding after_find callback extending object with self.class.extend_any
15
+ # default implementation of self.class.extend_any does nothing
16
+ included do
17
+ after_find {|obj| self.class.extend_any(obj) }
18
+ end
19
+
20
+ module ClassMethods
21
+
22
+ # This method could be used whenever there is a need for stubbing
23
+ # the exact ActiveRecord object attributes inside some execution flow
24
+ # __without__ underlying record change
25
+ def stub_orm_attr(id, obj_or_attributes )
26
+ stub(:extend_any, -> (obj) {
27
+ return unless obj.id == id && obj.is_a?( self )
28
+ obj.assign_attributes( obj_or_attributes.try(:attributes) || obj_or_attributes )
29
+ }) do
30
+ yield
31
+ end
32
+ end
33
+
34
+ # This method could be used whenever there is a need for stubbing
35
+ # the specific Active Record object's methods inside some flow piece
36
+ # with ANY way of object retrieval, making
37
+ def stub_orm_method(id, method, val_or_callable, *block_args )
38
+ stub(:extend_any, -> (obj) {
39
+ return unless obj.id == id && obj.is_a?( self )
40
+ define_stub_method(obj, method, val_or_callable, *block_args )
41
+ }) do
42
+ yield
43
+ end
44
+ ensure
45
+ undef_all(id, method)
46
+ end
47
+
48
+ private_class_method
49
+
50
+ def define_stub_method( object, method, val_or_callable, *block_args )
51
+ old_method = stub_method_name(method, obj: object)
52
+ object.singleton_class.send :alias_method, old_method, method
53
+ object.define_singleton_method method do |*args, &blk|
54
+ if val_or_callable.respond_to? :call
55
+ val_or_callable.call(*args, &blk)
56
+ else
57
+ blk.call(*block_args) if blk
58
+ val_or_callable
59
+ end
60
+ end
61
+ stubbed_objects(old_method) << object
62
+ end
63
+
64
+ def stub_method_name( method, obj: nil, id: nil)
65
+ # __stub_class_method_id
66
+ "__stub_#{to_s}_#{method}_#{obj&.id || id}"
67
+ end
68
+
69
+ def undef_all(id, method)
70
+ old_method = stub_method_name( method, id: id)
71
+ stubbed_objects(old_method).map(&:singleton_class).each do |metaclass|
72
+ metaclass.send :undef_method, method
73
+ metaclass.send :alias_method, method, old_method
74
+ metaclass.send :undef_method, old_method
75
+ end
76
+ end
77
+
78
+ def stubbed_objects(method_name)
79
+ (@@extended_obj ||= {})[method_name] ||= []
80
+ end
81
+
82
+ def extend_any(_obj); :do_nothing end
83
+ end
84
+ end if defined?(ActiveSupport::Concern)
@@ -0,0 +1,84 @@
1
+ module Stubberry::Object
2
+ # a copy/paste of an Objects stub method enriched with
3
+ # raise error functionality whenever stubbed method wasn't called
4
+ def stub_must( name, val_or_callable, *block_args )
5
+ new_name = "__minitest_stub__#{name}"
6
+ call_happened_method_name = "__#{name}_call_happened"
7
+
8
+ metaclass = class << self; self; end
9
+
10
+ if respond_to? name and not methods.map(&:to_s).include? name.to_s then
11
+ metaclass.send :define_method, name do |*args|
12
+ super(*args)
13
+ end
14
+ end
15
+
16
+ metaclass.send :alias_method, new_name, name
17
+
18
+ # this will make a closure without spoiling class with any instance vars and so
19
+ call_happened = []
20
+ metaclass.send :define_method, call_happened_method_name do
21
+ call_happened << true
22
+ end
23
+
24
+ metaclass.send :define_method, name do |*args, &blk|
25
+ __send__(call_happened_method_name)
26
+
27
+ if val_or_callable.respond_to? :call then
28
+ val_or_callable.call(*args, &blk)
29
+ else
30
+ blk.call(*block_args) if blk
31
+ val_or_callable
32
+ end
33
+ end
34
+
35
+ (yield self).tap do
36
+ raise "#{name} wasn't called" if call_happened.length == 0
37
+ end
38
+ ensure
39
+ metaclass.send :undef_method, name
40
+ metaclass.send :alias_method, name, new_name
41
+ metaclass.send :undef_method, new_name
42
+ metaclass.send :undef_method, call_happened_method_name
43
+ end
44
+
45
+ # the reverse method of stub_must -- will raise an issue whenever method
46
+ # was called inside a stubbing block
47
+ def stub_must_not( name, message = nil )
48
+ new_name = "__minitest_stub__#{name}"
49
+
50
+ metaclass = class << self; self; end
51
+
52
+ if respond_to?(name) && !methods.map(&:to_s).include?( name.to_s )
53
+ metaclass.define_method( name ) { | *args | super(*args) }
54
+ end
55
+
56
+ metaclass.alias_method( new_name, name )
57
+ metaclass.define_method( name ) { |*| raise message || "#{name} was called!" }
58
+
59
+ yield self
60
+ ensure
61
+ metaclass.undef_method( name )
62
+ metaclass.alias_method( name, new_name )
63
+ metaclass.undef_method( new_name )
64
+ end
65
+
66
+ # just for fun multiple stub_must in one call
67
+ def stub_must_all( name_to_var_or_callable, &block )
68
+ name_to_var_or_callable.length == 1 ? stub_must( *name_to_var_or_callable.shift, &block )
69
+ : stub_must( *name_to_var_or_callable.shift ) { stub_must_all(name_to_var_or_callable, &block ) }
70
+ end
71
+
72
+ # stub only if respond otherwise just execute
73
+ def stub_if_def(name, val_or_callable, *block_args, &block)
74
+ respond_to?( name ) ? stub(name, val_or_callable, *block_args, &block) : yield
75
+ end
76
+
77
+ # stub_must only if respond otherwise just execute
78
+ def stub_must_if_def(name, val_or_callable, *block_args, &block)
79
+ # stub only if respond otherwise just execute
80
+ respond_to?( name ) ? stub_must(name, val_or_callable, *block_args, &block) : yield
81
+ end
82
+ end
83
+
84
+ Object.include(Stubberry::Object)
@@ -1,3 +1,3 @@
1
1
  module Stubberry
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/stubberry.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require "stubberry/version"
2
+ require "stubberry/object"
3
+ require "stubberry/active_record"
2
4
 
3
5
  module Stubberry
4
6
  class Error < StandardError; end
data/stubberry.gemspec CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |spec|
6
6
  spec.authors = ["alekseyl"]
7
7
  spec.email = ["leshchuk@gmail.com"]
8
8
 
9
- spec.summary = %q{This a small set of stub extensions to Object interface.}
10
- spec.description = %q{This a small set of stub extensions to Object interface. There will be stub_must, stub_must_not, stub_if_def, stub_any_ar methods on it }
9
+ spec.summary = %q{Ultimate collection of sweet stub methods for ruby test suits. Lets stub! }
10
+ spec.description = %q{This a ultimate set of stub extensions. Suggest any reasonable subbing and I'll try to merge it. It will start with: stub_must, stub_must_not, stub_if_def and many more }
11
11
  spec.homepage = "https://github.com/alekseyl/stubberry"
12
12
  spec.license = "MIT"
13
13
  spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
@@ -26,4 +26,15 @@ Gem::Specification.new do |spec|
26
26
  spec.bindir = "exe"
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
+
30
+ spec.required_ruby_version = '>= 2.4'
31
+ spec.add_development_dependency "activerecord", ">= 6.1"
32
+
33
+ spec.add_development_dependency "bundler", ">= 1"
34
+ spec.add_development_dependency "rake", ">= 12.3.3"
35
+ spec.add_development_dependency "minitest", "~> 5.0"
36
+ spec.add_development_dependency 'sqlite3'
37
+
38
+
39
+ spec.add_development_dependency "ruby_jard"
29
40
  end
metadata CHANGED
@@ -1,17 +1,102 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stubberry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - alekseyl
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-02 00:00:00.000000000 Z
12
- dependencies: []
13
- description: 'This a small set of stub extensions to Object interface. There will
14
- be stub_must, stub_must_not, stub_if_def, stub_any_ar methods on it '
11
+ date: 2021-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 12.3.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 12.3.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: ruby_jard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: 'This a ultimate set of stub extensions. Suggest any reasonable subbing
98
+ and I''ll try to merge it. It will start with: stub_must, stub_must_not, stub_if_def
99
+ and many more '
15
100
  email:
16
101
  - leshchuk@gmail.com
17
102
  executables: []
@@ -19,9 +104,8 @@ extensions: []
19
104
  extra_rdoc_files: []
20
105
  files:
21
106
  - ".gitignore"
22
- - ".idea/inspectionProfiles/profiles_settings.xml"
23
- - ".idea/workspace.xml"
24
107
  - ".travis.yml"
108
+ - CHANGELOG.md
25
109
  - CODE_OF_CONDUCT.md
26
110
  - Gemfile
27
111
  - LICENSE.txt
@@ -30,6 +114,8 @@ files:
30
114
  - bin/console
31
115
  - bin/setup
32
116
  - lib/stubberry.rb
117
+ - lib/stubberry/active_record.rb
118
+ - lib/stubberry/object.rb
33
119
  - lib/stubberry/version.rb
34
120
  - stubberry.gemspec
35
121
  homepage: https://github.com/alekseyl/stubberry
@@ -48,7 +134,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
48
134
  requirements:
49
135
  - - ">="
50
136
  - !ruby/object:Gem::Version
51
- version: 2.3.0
137
+ version: '2.4'
52
138
  required_rubygems_version: !ruby/object:Gem::Requirement
53
139
  requirements:
54
140
  - - ">="
@@ -58,5 +144,5 @@ requirements: []
58
144
  rubygems_version: 3.1.4
59
145
  signing_key:
60
146
  specification_version: 4
61
- summary: This a small set of stub extensions to Object interface.
147
+ summary: Ultimate collection of sweet stub methods for ruby test suits. Lets stub!
62
148
  test_files: []
@@ -1,5 +0,0 @@
1
- <component name="InspectionProjectProfileManager">
2
- <settings>
3
- <option name="PROJECT_PROFILE" />
4
- </settings>
5
- </component>
data/.idea/workspace.xml DELETED
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="PropertiesComponent">
4
- <property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
5
- <property name="nodejs_npm_path_reset_for_default_project" value="true" />
6
- <property name="settings.editor.selected.configurable" value="org.jetbrains.plugins.ruby.settings.RubyActiveModuleSdkConfigurable" />
7
- </component>
8
- </project>