rester 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: feecdb5b8bdfda29d9df2683370a79eb805365ef
4
- data.tar.gz: e56faba40a47774b17e4db017ec4b7b2fb09213a
3
+ metadata.gz: 00fb4dde16f074048bf41f0f245bfb9e7838fe57
4
+ data.tar.gz: 812ec217d03ff554627fd79713fd1e15cec8ee9a
5
5
  SHA512:
6
- metadata.gz: 32e24fa563229bcad341c0b06668c67e93fd96196124bcc74e23a1b9d4222765a82d95179d97ad7b9a7430a9c78af85660c66620c433b49ae55ad21220b61aeb
7
- data.tar.gz: 57982fbf4923f471ddaf64387d4de8b4ede4c1f12f8654ca3dbdc963fa6490cb0998e19fe173099c4cde289bb6c381a9635c7e36f6df04eda300157af1e6ff0f
6
+ metadata.gz: 3753b97185a0000bcfc4368564873ff452c8ff989bd6f59d7a7959408b0346d3cbc4c61e6c6812ae138aefb63cf17f31be81ab8ee129a568bce1b51629609645
7
+ data.tar.gz: 2a24cbc7e691e0c64a93a6d35b97a94945614b6bf43284c28b126c9afbdfde34dc211dbd42f78f0288e2f8e2b62da8b96333224eb67b8c09ebb9767c46c9ee31
@@ -18,7 +18,7 @@ module Rester
18
18
  end # Class Methods
19
19
 
20
20
  def connect(stub_filepath, opts={})
21
- @stub = YAML.load_file(stub_filepath)
21
+ @stub = Utils::StubFile.new(stub_filepath)
22
22
  end
23
23
 
24
24
  def connected?
@@ -41,17 +41,17 @@ module Rester
41
41
  _request('DELETE', path, params)
42
42
  end
43
43
 
44
- def with_context(context, &block)
44
+ def with_context(context)
45
45
  @_context = context
46
- yield block
46
+ yield
47
47
  @_context = nil
48
48
  end
49
49
 
50
50
  private
51
51
 
52
52
  def _request(verb, path, params)
53
- response = _process_request(path, verb, params)
54
- [response['code'], response['body'].to_json]
53
+ spec = _process_request(path, verb, params)
54
+ [spec['response_code'], spec['response'].to_json]
55
55
  end
56
56
 
57
57
  def _process_request(path, verb, params)
@@ -72,9 +72,8 @@ module Rester
72
72
  end
73
73
 
74
74
  # At this point, the 'request' is valid by matching a corresponding
75
- # request in the stub yaml file. Grab the response from the file and
76
- # reset the context
77
- stub[path][verb][context]['response']
75
+ # request in the stub yaml file.
76
+ stub[path][verb][context]
78
77
  end
79
78
 
80
79
  ##
@@ -1,26 +1,32 @@
1
1
  module Rester
2
2
  class Client
3
- class Response < Hash
3
+ class Response
4
4
  def initialize(status, hash={})
5
5
  @_status = status
6
- merge!(hash)
7
- _deep_freeze
6
+ @_data = hash.dup || {}
7
+ Utils.deep_freeze(@_data)
8
+ freeze
8
9
  end
9
10
 
10
11
  def successful?
11
12
  @_status && @_status.between?(200, 299)
12
13
  end
13
14
 
14
- private
15
+ def to_h
16
+ @_data.dup
17
+ end
15
18
 
16
- def _deep_freeze(value=self)
17
- value.freeze
19
+ def ==(obj)
20
+ @_data == obj
21
+ end
22
+
23
+ private
18
24
 
19
- case value
20
- when Hash
21
- value.values.each { |v| _deep_freeze(v) }
22
- when Array
23
- value.each { |v| _deep_freeze(v) }
25
+ def method_missing(meth, *args, &block)
26
+ if @_data.respond_to?(meth)
27
+ @_data.public_send(meth, *args, &block)
28
+ else
29
+ super
24
30
  end
25
31
  end
26
32
  end # Response
data/lib/rester/rspec.rb CHANGED
@@ -4,12 +4,13 @@ RSpec.configure do |config|
4
4
  config.before :all, rester: // do |ex|
5
5
  # Load the stub file
6
6
  @rester_stub_filepath = ex.class.metadata[:rester]
7
- @rester_stub = YAML.load_file(@rester_stub_filepath)
7
+ @rester_stub = Rester::Utils::StubFile.new(@rester_stub_filepath)
8
8
 
9
9
  # Hook up the LocalAdapter with the Service being tested
10
10
  unless (klass = ex.class.described_class) < Rester::Service
11
11
  raise "invalid service to test"
12
12
  end
13
+
13
14
  @rester_adapter = Rester::Client::Adapters::LocalAdapter.new(klass, {})
14
15
 
15
16
  _validate_test_coverage(ex)
@@ -35,8 +36,7 @@ RSpec.configure do |config|
35
36
  }.compact
36
37
 
37
38
  begin
38
- stub_params = @rester_stub[path][verb][context]['request']
39
- raw_stub_response = @rester_stub[path][verb][context]['response']
39
+ spec = @rester_stub[path][verb][context]
40
40
  rescue NoMethodError
41
41
  fail Rester::Errors::StubError,
42
42
  "Could not find path: #{path.inspect} verb: #{verb.inspect} context: "\
@@ -47,7 +47,7 @@ RSpec.configure do |config|
47
47
  # Raw response from the service.
48
48
  # [HTTP CODE, JSON String]
49
49
  ex.example_group.let(:raw_service_response) {
50
- @rester_adapter.request(verb.downcase.to_sym, path, stub_params)
50
+ @rester_adapter.request(verb.downcase.to_sym, path, spec['request'])
51
51
  }
52
52
 
53
53
  ##
@@ -63,13 +63,12 @@ RSpec.configure do |config|
63
63
  ##
64
64
  # Expected response body specified in by the stub.
65
65
  ex.example_group.let(:stub_response) {
66
- JSON.parse((raw_stub_response['body'] || {}).to_json,
67
- symbolize_names: true)
66
+ JSON.parse((spec['response'] || {}).to_json, symbolize_names: true)
68
67
  }
69
68
 
70
69
  ##
71
70
  # HTTP status code expected by the stub.
72
- ex.example_group.let(:stub_response_code) { raw_stub_response['code'] }
71
+ ex.example_group.let(:stub_response_code) { spec['response_code'] }
73
72
 
74
73
  ##
75
74
  # Set the subject to be the service response (parsed ruby hash of the
@@ -1,12 +1,13 @@
1
1
  module Rester
2
2
  class Service::Resource
3
3
  class Params
4
+ DEFAULT_OPTS = { strict: true }.freeze
4
5
  BASIC_TYPES = [String, Symbol, Float, Integer].freeze
5
6
 
6
7
  attr_reader :options
7
8
 
8
9
  def initialize(opts={}, &block)
9
- @options = opts.dup.freeze
10
+ @options = DEFAULT_OPTS.merge(opts).freeze
10
11
  @_required_fields = []
11
12
  @_defaults = {}
12
13
  @_all_fields = []
@@ -64,7 +64,8 @@ module Rester
64
64
 
65
65
  def method_added(method_name)
66
66
  if RESOURCE_METHODS.include?(method_name.to_sym)
67
- method_params[method_name.to_sym] = (@_next_params || Params.new).freeze
67
+ method_params[method_name.to_sym] = (@_next_params ||
68
+ Params.new(strict: false)).freeze
68
69
  end
69
70
  @_next_params = nil
70
71
  end
@@ -0,0 +1,101 @@
1
+ module Rester
2
+ module Utils
3
+ class StubFile
4
+ DEFAULT_TAGS = { 'successful' => 'true' }.freeze
5
+
6
+ attr_reader :path
7
+
8
+ def initialize(path)
9
+ @path = path
10
+ @_stub = StubFile.parse(path)
11
+ end
12
+
13
+ private
14
+
15
+ def method_missing(meth, *args, &block)
16
+ if @_stub.respond_to?(meth)
17
+ @_stub.public_send(meth, *args, &block)
18
+ else
19
+ super
20
+ end
21
+ end
22
+
23
+ ##
24
+ # Class Methods
25
+ class << self
26
+ ##
27
+ # Parses the stub file and returns the data as a hash
28
+ def parse(path)
29
+ parse!(YAML.load_file(path))
30
+ end
31
+
32
+ ##
33
+ # Given a raw stub file hash, converts it to the format used internally.
34
+ def parse!(stub_hash)
35
+ stub_hash.each do |path, verbs|
36
+ next if ['version', 'consumer', 'producer'].include?(path)
37
+
38
+ verbs.each do |verb, contexts|
39
+ contexts.each do |context, spec|
40
+ _update_context(path, verb, context, spec)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ ##
47
+ # Given a context hash, updates it for consumption by the rest of the
48
+ # StubAdapter (i.e., removes tags from "response" key and puts them in
49
+ # a "response_tags" key).
50
+ def _update_context(path, verb, context, spec)
51
+ responses = spec.select { |k,_|
52
+ k =~ /\Aresponse(\[(\w+) *= *(\w+)(, *(\w+) *= *(\w+))*\])?\z/
53
+ }
54
+
55
+ if responses.count == 0
56
+ fail Errors::StubError, "#{verb.upcase} #{path} is missing a " \
57
+ "response for the context #{context.inspect}"
58
+ elsif responses.count > 1
59
+ fail Errors::StubError, "#{verb.upcase} #{path} has too many " \
60
+ "responses defined for the context #{context.inspect}"
61
+ end
62
+
63
+ response_key = responses.keys.first
64
+
65
+ tags = _parse_tags(path, verb, context, response_key)
66
+
67
+ spec.merge!(
68
+ 'response' => spec.delete(response_key),
69
+ 'response_tags' => tags,
70
+ 'response_code' => _parse_response_code(verb, tags)
71
+ )
72
+ end
73
+
74
+ ##
75
+ # Takes a response key (e.g., "response[successful=false]") and parses out
76
+ # the tags (e.g., {"successful" => false})
77
+ def _parse_tags(path, verb, context, resp_key)
78
+ DEFAULT_TAGS.merge(resp_key.scan(/(\w+) *= *(\w+)/).to_h).tap { |tags|
79
+ _validate_tags(path, verb, context, tags)
80
+ }
81
+ end
82
+
83
+ def _validate_tags(path, verb, context, tags)
84
+ unless ['true', 'false'].include?(tags['successful'])
85
+ fail Errors::StubError, '"successful" tag should be either "true" '\
86
+ 'or "false" in' "#{verb.upcase} #{path} in context " \
87
+ "#{context.inspect}"
88
+ end
89
+ end
90
+
91
+ def _parse_response_code(verb, tags)
92
+ if tags['successful'] == 'true'
93
+ (verb == 'POST') ? 201 : 200
94
+ else
95
+ 400
96
+ end
97
+ end
98
+ end # Class Methods
99
+ end # StubFile
100
+ end # Utils
101
+ end # Rester
data/lib/rester/utils.rb CHANGED
@@ -2,6 +2,8 @@ require 'date'
2
2
 
3
3
  module Rester
4
4
  module Utils
5
+ autoload(:StubFile, 'rester/utils/stub_file')
6
+
5
7
  class << self
6
8
  ##
7
9
  # Determines the HTTP method/verb based on the method name.
@@ -65,6 +67,17 @@ module Rester
65
67
  def underscore(str)
66
68
  str.scan(/[A-Z][a-z]*/).map(&:downcase).join('_')
67
69
  end
70
+
71
+ def deep_freeze(value)
72
+ value.freeze
73
+
74
+ case value
75
+ when Hash
76
+ value.values.each { |v| deep_freeze(v) }
77
+ when Array
78
+ value.each { |v| deep_freeze(v) }
79
+ end
80
+ end
68
81
  end # Class methods
69
82
  end # Utils
70
83
  end # Rester
@@ -1,3 +1,3 @@
1
1
  module Rester
2
- VERSION = '0.3.3'
2
+ VERSION = '0.4.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rester
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Honer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-11-13 00:00:00.000000000 Z
12
+ date: 2015-11-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -145,6 +145,7 @@ files:
145
145
  - lib/rester/service/resource.rb
146
146
  - lib/rester/service/resource/params.rb
147
147
  - lib/rester/utils.rb
148
+ - lib/rester/utils/stub_file.rb
148
149
  - lib/rester/version.rb
149
150
  homepage: http://github.com/payout/rester
150
151
  licenses: