fixturama 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/README.md +32 -4
  4. data/fixturama.gemspec +1 -1
  5. data/lib/fixturama.rb +48 -20
  6. data/lib/fixturama/changes.rb +71 -0
  7. data/lib/fixturama/changes/base.rb +28 -0
  8. data/lib/fixturama/changes/chain.rb +64 -0
  9. data/lib/fixturama/changes/chain/actions.rb +31 -0
  10. data/lib/fixturama/changes/chain/arguments.rb +59 -0
  11. data/lib/fixturama/changes/chain/raise_action.rb +35 -0
  12. data/lib/fixturama/changes/chain/return_action.rb +33 -0
  13. data/lib/fixturama/changes/const.rb +30 -0
  14. data/lib/fixturama/changes/request.rb +91 -0
  15. data/lib/fixturama/changes/request/response.rb +62 -0
  16. data/lib/fixturama/changes/request/responses.rb +22 -0
  17. data/lib/fixturama/changes/seed.rb +39 -0
  18. data/lib/fixturama/config.rb +5 -0
  19. data/lib/fixturama/fixture_error.rb +31 -0
  20. data/lib/fixturama/loader.rb +1 -0
  21. data/lib/fixturama/loader/context.rb +1 -0
  22. data/lib/fixturama/loader/value.rb +1 -0
  23. data/spec/fixturama/seed_fixture/_spec.rb +1 -0
  24. data/spec/fixturama/seed_fixture/seed.yml +0 -5
  25. metadata +34 -34
  26. data/lib/fixturama/seed.rb +0 -15
  27. data/lib/fixturama/stubs.rb +0 -79
  28. data/lib/fixturama/stubs/chain.rb +0 -90
  29. data/lib/fixturama/stubs/chain/actions.rb +0 -39
  30. data/lib/fixturama/stubs/chain/actions/raise.rb +0 -21
  31. data/lib/fixturama/stubs/chain/actions/return.rb +0 -23
  32. data/lib/fixturama/stubs/chain/arguments.rb +0 -86
  33. data/lib/fixturama/stubs/const.rb +0 -43
  34. data/lib/fixturama/stubs/request.rb +0 -98
  35. data/lib/fixturama/stubs/request/response.rb +0 -43
  36. data/lib/fixturama/stubs/request/responses.rb +0 -20
  37. data/lib/fixturama/utils.rb +0 -39
@@ -1,15 +0,0 @@
1
- module Fixturama
2
- module Seed
3
- module_function
4
-
5
- def call(opts)
6
- opts = Utils.symbolize_hash(opts)
7
- type = opts[:type].to_sym
8
- traits = Utils.symbolize_array opts[:traits]
9
- params = Utils.symbolize_hash opts[:params]
10
- count = opts.fetch(:count, 1).to_i
11
-
12
- FactoryBot.create_list(type, count, *traits, **params) if count.positive?
13
- end
14
- end
15
- end
@@ -1,79 +0,0 @@
1
- module Fixturama
2
- #
3
- # Collection of stubbed calls
4
- #
5
- class Stubs
6
- require_relative "stubs/chain"
7
- require_relative "stubs/const"
8
- require_relative "stubs/request"
9
-
10
- #
11
- # Register new action and apply the corresponding stub
12
- #
13
- # @params [Hash<#to_s, _>] options
14
- # @return [self] itself
15
- #
16
- def add(options)
17
- options = symbolize(options)
18
- find_or_create_stub!(options)&.update!(options)
19
- self
20
- end
21
-
22
- #
23
- # Applies the stub to RSpec example
24
- #
25
- def apply(example)
26
- @stubs.values.each { |stub| stub.apply!(example) }
27
- end
28
-
29
- private
30
-
31
- def initialize
32
- @stubs = {}
33
- end
34
-
35
- def find_or_create_stub!(options)
36
- stub = case stub_type(options)
37
- when :message_chain then Chain.new(options)
38
- when :constant then Const.new(options)
39
- when :request then Request.new(options)
40
- end
41
-
42
- @stubs[stub.key] ||= stub if stub
43
- end
44
-
45
- def stub_type(options)
46
- key = (TYPES.keys & options.keys).first
47
- return TYPES[key] if key
48
-
49
- raise ArgumentError, <<~MESSAGE
50
- Cannot figure out what to stub from #{options}.
51
- You should define either a class and a message chain, or some const.
52
- MESSAGE
53
- end
54
-
55
- # Matches keys to the type of the stub
56
- TYPES = {
57
- arguments: :message_chain,
58
- actions: :message_chain,
59
- basic_auth: :request,
60
- body: :request,
61
- chain: :message_chain,
62
- class: :message_chain,
63
- const: :constant,
64
- headers: :request,
65
- http_method: :request,
66
- object: :message_chain,
67
- query: :request,
68
- response: :request,
69
- responses: :request,
70
- uri: :request,
71
- url: :request,
72
- value: :constant,
73
- }.freeze
74
-
75
- def symbolize(options)
76
- Hash(options).transform_keys { |key| key.to_s.to_sym }
77
- end
78
- end
79
- end
@@ -1,90 +0,0 @@
1
- module Fixturama
2
- #
3
- # Stubbed chain of messages
4
- #
5
- class Stubs::Chain
6
- require_relative "chain/actions"
7
- require_relative "chain/arguments"
8
-
9
- attr_reader :receiver, :messages
10
-
11
- #
12
- # Human-readable representation of the chain
13
- # @return [String]
14
- #
15
- def to_s
16
- "#{receiver}.#{messages.join(".")}"
17
- end
18
- alias to_str to_s
19
- alias key to_s
20
-
21
- #
22
- # Register new action for some arguments
23
- #
24
- # @option [Array<#to_s>, #to_s] :arguments The specific arguments
25
- # @option (see Fixturama::Stubs::Arguments#add_action)
26
- # @return [self]
27
- #
28
- def update!(actions:, arguments: nil, **)
29
- Utils.array(arguments).tap do |args|
30
- stub = find_by(args)
31
- unless stub
32
- stub = Stubs::Chain::Arguments.new(self, args)
33
- stubs << stub
34
- end
35
- stub.add!(*actions)
36
- stubs.sort_by! { |stub| -stub.arguments.count }
37
- end
38
-
39
- self
40
- end
41
-
42
- #
43
- # Apply the stub to RSpec example
44
- #
45
- def apply!(example)
46
- reset!
47
-
48
- call_action = example.send(:receive_message_chain, *messages) do |*args|
49
- call! args
50
- end
51
-
52
- example.send(:allow, receiver).to call_action
53
- end
54
-
55
- private
56
-
57
- def initialize(**options)
58
- @receiver = Utils.constantize options[:class] if options.key?(:class)
59
- @receiver ||= Object.send :eval, options[:object] if options.key?(:object)
60
- raise SyntaxError, "Undefined receiver of messages" unless receiver
61
-
62
- @messages = Utils.symbolize_array options[:chain]
63
- return if messages.any?
64
-
65
- raise SyntaxError, <<~MESSAGE.squish
66
- Undefined message chain for stubbing #{receiver}.
67
- Use option `chain` to define it.
68
- MESSAGE
69
- end
70
-
71
- def stubs
72
- @stubs ||= []
73
- end
74
-
75
- def find_by(arguments)
76
- stubs.find { |stub| stub.arguments == arguments }
77
- end
78
-
79
- def reset!
80
- tap { stubs.each(&:reset!) }
81
- end
82
-
83
- def call!(actual_arguments)
84
- stub = stubs.find { |item| item.applicable_to?(actual_arguments) }
85
- raise "Unexpected arguments #{actual_arguments}" unless stub
86
-
87
- stub.call_next!
88
- end
89
- end
90
- end
@@ -1,39 +0,0 @@
1
- module Fixturama
2
- #
3
- # Factory to provide a specific action from options
4
- #
5
- module Stubs::Chain::Actions
6
- extend self
7
-
8
- require_relative "actions/raise"
9
- require_relative "actions/return"
10
-
11
- #
12
- # Builds an action
13
- # @option [#to_s] :raise
14
- # @option [Object] :return
15
- # @option [true] :call_original
16
- # @return [#call] a callable action
17
- #
18
- def build(stub, **options)
19
- check!(stub, options)
20
- key, value = options.to_a.first
21
- TYPES[key].new(stub, value)
22
- end
23
-
24
- private
25
-
26
- def check!(stub, options)
27
- keys = options.keys & TYPES.keys
28
- return if keys.count == 1
29
-
30
- raise SyntaxError, <<~MESSAGE.squish
31
- Invalid settings for stubbing message chain #{stub}: #{options}.
32
- The action MUST have one and only one of the keys:
33
- `#{TYPES.keys.join('`, `')}`.
34
- MESSAGE
35
- end
36
-
37
- TYPES = { raise: Raise, return: Return }.freeze
38
- end
39
- end
@@ -1,21 +0,0 @@
1
- class Fixturama::Stubs::Chain::Actions::Raise
2
- def call
3
- raise @exception
4
- end
5
-
6
- #
7
- # Human-readable representation of the expectation
8
- # @return [String]
9
- #
10
- def to_s
11
- "#{@stub} # raise #{@exception}"
12
- end
13
-
14
- private
15
-
16
- def initialize(stub, name)
17
- @stub = stub
18
- name = name.to_s
19
- @exception = name == "true" ? StandardError : Kernel.const_get(name)
20
- end
21
- end
@@ -1,23 +0,0 @@
1
- class Fixturama::Stubs::Chain::Actions::Return
2
- attr_reader :stub, :call
3
-
4
- #
5
- # Human-readable representation of the expectation
6
- # @return [String]
7
- #
8
- def to_s
9
- "#{@stub} # => #{call}"
10
- end
11
-
12
- private
13
-
14
- def initialize(stub, output)
15
- @stub = stub
16
- @call = \
17
- begin # in ruby 2.3.0 Fixnum#dup is defined, but raises TypeError
18
- output.respond_to?(:dup) ? output.dup : output
19
- rescue TypeError
20
- output
21
- end
22
- end
23
- end
@@ -1,86 +0,0 @@
1
- module Fixturama
2
- #
3
- # Collection of arguments for a stub with a list of actions to be called
4
- #
5
- class Stubs::Chain::Arguments
6
- attr_reader :chain, :arguments
7
-
8
- #
9
- # Register new action for these set of arguments
10
- # @option [#to_i] :repeat (1)
11
- # How much the action should be repeated during the consecutive calls
12
- # @return [self] itself
13
- #
14
- def add!(*actions)
15
- actions.each do |settings|
16
- settings = Utils.symbolize_hash(settings)
17
- repeat = [0, settings.fetch(:repeat, 1).to_i].max
18
- repeat.times { list << Stubs::Chain::Actions.build(self, settings) }
19
- end
20
-
21
- self
22
- end
23
-
24
- #
25
- # Whether the current stub is applicable to actual arguments
26
- # @param [Array<Object>] actual_arguments
27
- # @return [Boolean]
28
- #
29
- def applicable_to?(actual_arguments)
30
- last_index = actual_arguments.count
31
- @arguments.zip(actual_arguments)
32
- .each.with_index(1)
33
- .reduce(true) do |obj, ((expected, actual), index)|
34
- obj && (
35
- expected == actual ||
36
- index == last_index &&
37
- Fixturama::Utils.matched_hash_args?(actual, expected)
38
- )
39
- end
40
- end
41
-
42
- #
43
- # Reset the counter of calls
44
- # @return [self] itself
45
- #
46
- def reset!
47
- @counter = 0
48
- self
49
- end
50
-
51
- #
52
- # Calls the next action for these set of agruments
53
- # @return [Object]
54
- # @raise [StandardError]
55
- #
56
- def call_next!
57
- list.fetch(counter) { list.last }.call.tap { @counter += 1 }
58
- end
59
-
60
- #
61
- # Human-readable representation of arguments
62
- # @return [String]
63
- #
64
- def to_s
65
- args = [*arguments.map(&:to_s), "*"].join(", ")
66
- "#{chain}(#{args})"
67
- end
68
-
69
- private
70
-
71
- # @param [Fixturama::Stubs::Chain] chain Back reference
72
- # @param [Array<Object>] list Definition of arguments
73
- def initialize(chain, list)
74
- @chain = chain
75
- @arguments = Utils.array(list)
76
- end
77
-
78
- def counter
79
- @counter ||= 0
80
- end
81
-
82
- def list
83
- @list ||= []
84
- end
85
- end
86
- end
@@ -1,43 +0,0 @@
1
- module Fixturama
2
- #
3
- # Definition for stubbing a constant
4
- #
5
- class Stubs::Const
6
- attr_reader :const, :value
7
-
8
- #
9
- # Human-readable representation of the chain
10
- # @return [String]
11
- #
12
- def to_s
13
- const.to_s
14
- end
15
- alias to_str to_s
16
- alias key to_s
17
-
18
- #
19
- # Overload the definition for the constant
20
- # @option [Object] value
21
- # @return [self]
22
- #
23
- def update!(value:, **)
24
- @value = value
25
- self
26
- end
27
-
28
- #
29
- # Apply the stub to RSpec example
30
- # @return [self]
31
- #
32
- def apply!(example)
33
- example.send(:stub_const, const, value)
34
- self
35
- end
36
-
37
- private
38
-
39
- def initialize(const:, **)
40
- @const = const.to_s
41
- end
42
- end
43
- end
@@ -1,98 +0,0 @@
1
- #
2
- # Stubbed request
3
- #
4
- class Fixturama::Stubs::Request
5
- require_relative "request/response"
6
- require_relative "request/responses"
7
-
8
- def to_s
9
- "#{http_method.upcase} #{uri.to_s == "" ? "*" : uri}"
10
- end
11
- alias to_str to_s
12
-
13
- # every stub is unique
14
- alias key hash
15
- def update!(_); end
16
-
17
- def apply!(example)
18
- stub = example.stub_request(http_method, uri)
19
- stub = stub.with(request) if request.any?
20
- stub.to_return { |_| responses.next }
21
- end
22
-
23
- private
24
-
25
- attr_reader :options
26
-
27
- def initialize(options)
28
- @options = options
29
- with_error { @options = Hash(options).symbolize_keys }
30
- end
31
-
32
- HTTP_METHODS = %i[get post put patch delete head options any].freeze
33
-
34
- def http_method
35
- value = with_error("method") { options[:method]&.to_sym&.downcase } || :any
36
- return value if HTTP_METHODS.include?(value)
37
-
38
- raise ArgumentError, "Invalid HTTP method #{value} in #{@optons}"
39
- end
40
-
41
- def uri
42
- with_error("uri") { maybe_regexp(options[:uri] || options[:url]) }
43
- end
44
-
45
- def headers
46
- with_error("headers") do
47
- Hash(options[:headers]).transform_keys(&:to_s) if options.key?(:headers)
48
- end
49
- end
50
-
51
- def query
52
- with_error("query") do
53
- Hash(options[:query]).transform_keys(&:to_s) if options.key?(:query)
54
- end
55
- end
56
-
57
- def body
58
- with_error("body") do
59
- case options[:body]
60
- when NilClass then nil
61
- when Hash then options[:body]
62
- else maybe_regexp(options[:body])
63
- end
64
- end
65
- end
66
-
67
- def basic_auth
68
- with_error("basic auth") do
69
- value = options[:auth] || options[:basic_auth]
70
- Hash(value).transform_keys(&:to_s).values_at("user", "pass") if value
71
- end
72
- end
73
-
74
- def request
75
- @request ||= {
76
- headers: headers,
77
- body: body,
78
- query: query,
79
- basic_auth: basic_auth
80
- }.select { |_, val| val }
81
- end
82
-
83
- def responses
84
- @responses ||= Responses.new(options[:response] || options[:responses])
85
- end
86
-
87
- def with_error(part = nil)
88
- yield
89
- rescue RuntimeError
90
- message = ["Cannot extract a request", part, "from #{options}"].join(" ")
91
- raise ArgumentError, message, __FILE__, __LINE__ - 1
92
- end
93
-
94
- def maybe_regexp(str)
95
- str = str.to_s
96
- str[%r{\A/.*/\z}] ? Regexp.new(str[1..-2]) : str
97
- end
98
- end