response_mate 0.3.3 → 0.4.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.
@@ -2,15 +2,14 @@ class ResponseMate::Commands::Inspect < ResponseMate::Commands::Base
2
2
  attr_reader :inspector
3
3
  attr_accessor :history
4
4
 
5
- def initialize(args, options)
6
- super(args, options)
5
+ def run # rubocop:disable Metrics/AbcSize
6
+ environment = ResponseMate::Environment.new(options[:environment])
7
+ options[:manifest] = ResponseMate::Manifest.new(options[:requests_manifest],
8
+ environment)
7
9
 
8
- @options[:manifest] = ResponseMate::Manifest.new(options[:requests_manifest])
9
- @inspector = ResponseMate::Inspector.new(@options)
10
+ @inspector = ResponseMate::Inspector.new(options)
10
11
  @history = []
11
- end
12
12
 
13
- def run
14
13
  if args.empty?
15
14
  return $stderr.puts 'At least one key has to be specified'.red
16
15
  end
@@ -1,15 +1,14 @@
1
1
  # Command which performs the operations required by `response_mate list`
2
2
  class ResponseMate::Commands::List < ResponseMate::Commands::Base
3
3
  # Run the command based on args, options provided
4
- def run
4
+ def run # rubocop:disable Metrics/AbcSize
5
5
  environment = ResponseMate::Environment.new(options[:environment])
6
- @manifest = ResponseMate::Manifest.new(options[:requests_manifest], environment)
7
-
8
- available_keys = @manifest.requests.map { |r| r.key.to_sym }
6
+ options[:manifest] = ResponseMate::Manifest.new(options[:requests_manifest],
7
+ environment)
9
8
 
10
9
  puts available_keys.join("\n") << "\n\n"
11
-
12
10
  action = ask_action
11
+
13
12
  return if action == :no
14
13
 
15
14
  perform_action(action, ask_key(available_keys))
@@ -17,6 +16,10 @@ class ResponseMate::Commands::List < ResponseMate::Commands::Base
17
16
 
18
17
  private
19
18
 
19
+ def available_keys
20
+ options[:manifest].requests.map { |r| r.key.to_sym }
21
+ end
22
+
20
23
  def ask_action
21
24
  choose do |menu|
22
25
  menu.prompt = 'Want to perform any of the actions above?'
@@ -34,9 +37,9 @@ class ResponseMate::Commands::List < ResponseMate::Commands::Base
34
37
  def perform_action(action, key)
35
38
  case action
36
39
  when :record
37
- ResponseMate::Recorder.new(manifest: @manifest).record([key])
40
+ ResponseMate::Recorder.new(options).record([key])
38
41
  when :inspect
39
- ResponseMate::Inspector.new(manifest: @manifest).inspect_key(key)
42
+ ResponseMate::Inspector.new(options).inspect_key(key)
40
43
  end
41
44
  end
42
45
  end
@@ -3,9 +3,8 @@ class ResponseMate::Commands::Record < ResponseMate::Commands::Base
3
3
  # Run the command based on args, options provided
4
4
  def run
5
5
  environment = ResponseMate::Environment.new(options[:environment])
6
- manifest = ResponseMate::Manifest.new(options[:requests_manifest], environment)
7
-
8
- options[:manifest] = manifest
6
+ options[:manifest] = ResponseMate::Manifest.new(options[:requests_manifest],
7
+ environment)
9
8
 
10
9
  recorder = ResponseMate::Recorder.new(options)
11
10
 
@@ -14,7 +14,7 @@ class ResponseMate::Connection
14
14
 
15
15
  # Performs the supplied request
16
16
  # @param {ResponseMate::Request} The request to be performed
17
- def fetch(request)
17
+ def fetch(request) # rubocop:disable Metrics/AbcSize
18
18
  uri = URI.parse(request[:url])
19
19
 
20
20
  if request[:params]
@@ -23,10 +23,8 @@ class ResponseMate::Connection
23
23
  uri.query = query
24
24
  end
25
25
 
26
- verb = request[:verb] || 'GET'
27
-
28
26
  client.headers = request[:headers] if request[:headers]
29
- client.send verb.downcase.to_sym, uri.to_s
27
+ client.send request[:verb].downcase.to_sym, uri.to_s
30
28
  rescue Faraday::Error::ConnectionFailed
31
29
  puts "Is a server up and running at #{request[:path]}?".red
32
30
  exit 1
@@ -1,17 +1,18 @@
1
1
  # The main module of the tool contains configuration code and some constants
2
2
  module ResponseMate
3
3
  class OutputDirError < StandardError; end
4
+ class ManifestMissing < StandardError; end
4
5
  class KeysNotFound < StandardError; end
5
6
 
6
7
  # Methods handled by response_mate
7
- HTTP_METHODS = %w[GET POST PUT PATCH DELETE HEAD OPTIONS]
8
+ HTTP_METHODS = Faraday::Connection::METHODS
8
9
 
9
10
  # Responsible for keeping initialization configuration values
10
11
  class Configuration
11
12
  attr_accessor :output_dir, :requests_manifest, :environment
12
13
 
13
14
  def initialize
14
- @output_dir = './output/responses/'
15
+ @output_dir = './'
15
16
  @requests_manifest = './requests.yml'
16
17
  @environment = './environment.yml'
17
18
  end
@@ -3,26 +3,26 @@
3
3
  # is a Hash which will be used for the rendering of the requests manifest as a
4
4
  # [Mustace template](http://mustache.github.io/mustache.5.html).
5
5
  class ResponseMate::Environment
6
- attr_accessor :filename, :env, :environment_text
6
+ attr_accessor :filename, :env
7
7
 
8
8
  delegate :[], to: :env
9
9
 
10
10
  def initialize(filename)
11
11
  @filename = filename || ResponseMate.configuration.environment
12
- @env = {}
13
12
  parse
14
13
  end
15
14
 
15
+ # Check for environment file existence
16
+ # @return [TrueClass|FalseClass]
17
+ def exists?
18
+ File.exist? filename
19
+ end
20
+
16
21
  private
17
22
 
23
+ # Set the env to the parsed YAML environment file
18
24
  def parse
19
- begin
20
- @environment_text = File.read filename
21
- rescue Errno::ENOENT
22
- puts filename.red << ' does not seem to exist'
23
- exit 1
24
- end
25
-
26
- @env = ::YAML.load(environment_text)
25
+ return @env = {} unless exists?
26
+ @env = ::YAML.load_file(filename)
27
27
  end
28
28
  end
@@ -13,8 +13,9 @@ module ResponseMate
13
13
 
14
14
  # Returns the compatible transformed resource
15
15
  def export
16
- @handler = "ResponseMate::Exporters::#{format.capitalize}".safe_constantize.
17
- new manifest, environment, resource
16
+ @handler = "ResponseMate::Exporters::#{format.capitalize}".safe_constantize.new manifest,
17
+ environment,
18
+ resource
18
19
  handler.export
19
20
  end
20
21
  end
@@ -20,7 +20,7 @@ class ResponseMate::Exporters::Postman
20
20
  private
21
21
 
22
22
  def build_structure
23
- timestamp = Time.now.strftime("%Y%m%d%H%M%S")
23
+ timestamp = Time.now.strftime('%Y%m%d%H%M%S')
24
24
 
25
25
  out.merge!(
26
26
  id: SecureRandom.uuid,
@@ -10,29 +10,17 @@ class ResponseMate::Manifest
10
10
  parse
11
11
  end
12
12
 
13
- # Parse the requests manifest
14
- # @return [Array] of requests
15
- def parse
16
- preprocess_manifest
17
- @request_hashes = YAML.load(requests_text).deep_symbolize_keys
18
- @name = @request_hashes[:name] || filename
19
- @description = @request_hashes[:description] || ''
20
- @requests = @request_hashes[:requests].
21
- map(&:deep_symbolize_keys!).
22
- map { |rh| ResponseMate::Request.new(rh).normalize! }
23
- end
24
-
25
13
  # Filters requests based on the supplied Array of keys
26
14
  # @param [Array] keys The keys to lookup for matching requests
27
15
  # @return [Array] of matching requests
28
16
  def requests_for_keys(keys)
29
- return [] if keys.empty?
17
+ return [] if keys.blank?
30
18
 
31
19
  existing_keys = requests.map(&:key)
32
20
  missing_keys = keys - existing_keys
33
21
 
34
22
  if missing_keys.present?
35
- fail ResponseMate::KeysNotFound.new(missing_keys.join(','))
23
+ fail ResponseMate::KeysNotFound.new(missing_keys.join(', '))
36
24
  end
37
25
 
38
26
  requests.select! do |r|
@@ -42,18 +30,69 @@ class ResponseMate::Manifest
42
30
 
43
31
  private
44
32
 
33
+ # Parse the requests manifest
34
+ # @return [Array] of requests
35
+ def parse
36
+ preprocess_manifest
37
+ parsed_manifest = YAML.load(@requests_text).deep_symbolize_keys
38
+ @name = parsed_manifest.fetch(:name, filename)
39
+ @description = parsed_manifest.fetch(:description, '')
40
+ check_requests(parsed_manifest)
41
+ @requests = parsed_manifest.
42
+ fetch(:requests, []). # rubocop:disable Style/MultilineOperationIndentation
43
+ map(&:deep_symbolize_keys!). # rubocop:disable Style/MultilineOperationIndentation
44
+ map { |rh| ResponseMate::Request.new(rh).normalize! } # rubocop:disable Style/MultilineOperationIndentation
45
+ end
46
+
45
47
  # Parse the manifest file as a template
46
48
  # @return [String] The manifest text parsed as a template
47
49
  def preprocess_manifest
48
50
  begin
49
51
  @requests_text = File.read filename
50
52
  rescue Errno::ENOENT
51
- puts filename.red << ' does not seem to exist'
52
- exit 1
53
+ raise ResponseMate::ManifestMissing.new(filename)
53
54
  end
54
55
 
55
- if environment.present? # rubocop:disable Style/GuardClause
56
- @requests_text = Mustache.render(@requests_text, environment.try(:env) || {})
57
- end
56
+ process_mustache! if environment.present? && mustache?
57
+ end
58
+
59
+ # Check if the manifest file is a Mustache template
60
+ def mustache?
61
+ requests_text =~ /{{.*}}/
62
+ end
63
+
64
+ # Evaluate Mustache template
65
+ def process_mustache!
66
+ check_environment
67
+
68
+ @requests_text = Mustache.render(requests_text, environment.env)
69
+ end
70
+
71
+ def check_environment
72
+ return if environment.exists?
73
+
74
+ warning = 'The specified requests file is a template, but no environment file is found.'
75
+ guide = <<-GUIDE
76
+ The environment file holds any variables you wish to be interpolated.
77
+ You may specify a different environment file using the -e [file.yml] option.
78
+ Default: environment.yml
79
+ GUIDE
80
+
81
+ STDERR.puts warning.yellow, guide
82
+ end
83
+
84
+ def check_requests(parsed_manifest)
85
+ return if parsed_manifest.key? :requests
86
+
87
+ gemspec = Gem::Specification.find_by_name('response_mate')
88
+ example_manifest = "#{gemspec.homepage}/blob/master/requests.yml.sample"
89
+
90
+ warning = 'The specified requests file contains no requests.'
91
+ guide = <<-GUIDE
92
+ To declare requests place them under the :requests key.
93
+ Example manifest: #{example_manifest}
94
+ GUIDE
95
+
96
+ STDERR.puts warning.yellow, guide
58
97
  end
59
98
  end
@@ -5,9 +5,10 @@ class ResponseMate::Request < OpenStruct
5
5
 
6
6
  # Make sure all defined requests in the manifest have complete
7
7
  # information for {ResponseMate::Connection#fetch}
8
- def normalize!
9
- unless ResponseMate::HTTP_METHODS.include? request[:verb]
10
- request[:verb] = 'GET'
8
+ def normalize! # rubocop:disable Metrics/AbcSize
9
+ request[:verb] = begin
10
+ (ResponseMate::HTTP_METHODS & [request.fetch(:verb, 'GET').downcase.to_sym]).first ||
11
+ 'GET'
11
12
  end
12
13
 
13
14
  if request[:url] !~ /{{.*?}}/ # Avoid encoding unprocessed mustache tags
@@ -18,8 +19,9 @@ class ResponseMate::Request < OpenStruct
18
19
  end
19
20
 
20
21
  # @return [String] Output string suitable for a terminal
21
- def to_cli_format
22
- out = "[#{key}] #{request[:verb]}".cyan_on_black.bold << " #{request[:url]}"
22
+ def to_cli_format # rubocop:disable Metrics/AbcSize
23
+ out = ["[#{key.yellow}] ", request[:verb].to_s.upcase.colorize(:cyan).on_black.bold,
24
+ " #{request[:url]}"].join
23
25
  out << "\tparams #{request[:params]}" if request[:params].present?
24
26
  out
25
27
  end
@@ -1,7 +1,7 @@
1
1
  # Responsible for the recorded responses as files
2
2
  class ResponseMate::Tape
3
3
  # Writes the tape as a file
4
- def write(key, request, response, meta = {}, output_dir = nil)
4
+ def write(key, request, response, meta = {}, output_dir = nil) # rubocop:disable Metrics/AbcSize
5
5
  output_dir ||= ResponseMate.configuration.output_dir
6
6
 
7
7
  output_path = File.join output_dir, "#{key}.yml"
@@ -22,21 +22,22 @@ class ResponseMate::Tape
22
22
  f << file_content.to_yaml
23
23
  end
24
24
  rescue Errno::ENOENT
25
- raise ResponseMate::OutputDirError
25
+ raise ResponseMate::OutputDirError.new(output_dir)
26
26
  end
27
27
 
28
28
  private
29
29
 
30
30
  def _utf8_encode(object)
31
- case object
32
- when String
33
- object.force_encoding('UTF-8')
34
- when Hash
35
- object.each do |k, v| # rubocop:disable Lint/UnusedBlockArgument
36
- k = _utf8_encode(v) # rubocop:disable Lint/UselessAssignment
37
- v = _utf8_encode(v) # rubocop:disable Lint/UselessAssignment
31
+ if object.respond_to? :force_encoding
32
+ object.force_encoding('UTF-8').encode!
33
+ elsif object.is_a? Hash
34
+ object.reduce({}) do |h, (k, v)|
35
+ key = k.dup unless k.is_a? Symbol
36
+
37
+ h[_utf8_encode(key)] = _utf8_encode(v)
38
+ h
38
39
  end
39
- when Array
40
+ elsif object.respond_to? :each
40
41
  object.each { |v| _utf8_encode(v) }
41
42
  end
42
43
  end
@@ -1,4 +1,4 @@
1
1
  module ResponseMate
2
2
  # Gem version
3
- VERSION = '0.3.3'
3
+ VERSION = '0.4.0'
4
4
  end
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency 'thor', '~> 0.19'
27
27
  spec.add_dependency 'awesome_print'
28
28
  spec.add_dependency 'activesupport'
29
- spec.add_dependency 'colored'
29
+ spec.add_dependency 'colorize', '> 0.7.5'
30
30
  spec.add_dependency 'faraday'
31
31
  spec.add_dependency 'faraday_middleware'
32
32
  spec.add_dependency 'addressable'
@@ -3,9 +3,11 @@ require 'spec_helper'
3
3
  describe ResponseMate::Commands::List do
4
4
  include_context 'stubbed_requests'
5
5
 
6
- subject { ResponseMate::Commands::List.new([], {}) }
6
+ let(:options) { {} }
7
7
  let(:cmd_output) { capture(:stdout) { subject.run } }
8
8
 
9
+ subject(:command) { ResponseMate::Commands::List.new([], options) }
10
+
9
11
  describe '#run' do
10
12
  before { subject.stub(:ask_action).and_return(:no) }
11
13
 
@@ -23,6 +25,47 @@ describe ResponseMate::Commands::List do
23
25
  quietly { cmd_output }
24
26
  expect(File.basename(output_files.call.last)).to eq('user_friends.yml')
25
27
  end
28
+
29
+ describe 'output directory' do
30
+ context 'when the output_dir option is specified' do
31
+ let(:custom_output_dir) do
32
+ File.expand_path('spec/source/other_output_dir')
33
+ end
34
+
35
+ let(:options) { { output_dir: custom_output_dir } }
36
+
37
+ context 'and it exists' do
38
+ let(:output_files) { -> { Dir[custom_output_dir + '/*'] } }
39
+
40
+ after { output_files.call.each { |file| File.delete(file) } }
41
+
42
+ it 'places the tapes in the specified directory' do
43
+ quietly { command.run }
44
+
45
+ expect(output_files.call.size).to eq(1)
46
+ end
47
+ end
48
+
49
+ context 'and it does not exist' do
50
+ let(:custom_output_dir) do
51
+ File.expand_path('spec/source/i_do_not_exist')
52
+ end
53
+
54
+ it 'raises ResponeMate::OutputDirError' do
55
+ expect { quietly { command.run } }.to raise_error(ResponseMate::OutputDirError,
56
+ /#{custom_output_dir}/)
57
+ end
58
+ end
59
+ end
60
+
61
+ context 'when the output_dir options is not specified' do
62
+ it 'places the tapes in the default output directory' do
63
+ quietly { command.run }
64
+
65
+ expect(output_files.call.size).to eq(1)
66
+ end
67
+ end
68
+ end
26
69
  end
27
70
  end
28
71
 
@@ -10,8 +10,10 @@ describe ResponseMate::Commands::Record do
10
10
  end
11
11
 
12
12
  describe 'output files' do
13
+ subject { output_files.call }
14
+
13
15
  it 'creates on for each request' do
14
- expect(output_files.call).to have_exactly(2).items
16
+ expect(subject.size).to eq(2)
15
17
  end
16
18
  end
17
19
  end
@@ -24,7 +26,7 @@ describe ResponseMate::Commands::Record do
24
26
  let(:cmd_with_output_dir) do
25
27
  quietly do
26
28
  ResponseMate::Commands::Record.new([], keys: [],
27
- output_dir: [other_output_dir]).run
29
+ output_dir: other_output_dir).run
28
30
  end
29
31
  end
30
32
 
@@ -34,8 +36,8 @@ describe ResponseMate::Commands::Record do
34
36
  before { cmd_with_output_dir }
35
37
  after { output_files.call.each { |file| File.delete(file) } }
36
38
 
37
- it 'created the tapes in the specified directory' do
38
- expect(output_files.call).to have_exactly(2).items
39
+ it 'creates the tapes in the specified directory' do
40
+ expect(output_files.call.size).to eq(2)
39
41
  end
40
42
  end
41
43
 
@@ -45,7 +47,8 @@ describe ResponseMate::Commands::Record do
45
47
  end
46
48
 
47
49
  it 'raises ResponeMate::OutputDirError' do
48
- expect { cmd_with_output_dir }.to raise_error(ResponseMate::OutputDirError)
50
+ expect { cmd_with_output_dir }.to raise_error(ResponseMate::OutputDirError,
51
+ /#{other_output_dir}/)
49
52
  end
50
53
  end
51
54
  end
@@ -54,7 +57,7 @@ describe ResponseMate::Commands::Record do
54
57
  it 'creates the tapes in the default output directory' do
55
58
  quietly { ResponseMate::Commands::Record.new([], keys: []).run }
56
59
 
57
- expect(output_files.call).to have_exactly(2).items
60
+ expect(output_files.call.size).to eq(2)
58
61
  end
59
62
  end
60
63
 
@@ -67,7 +70,7 @@ describe ResponseMate::Commands::Record do
67
70
  end
68
71
 
69
72
  it 'creates an output response file' do
70
- expect(output_files.call).to have_exactly(1).items
73
+ expect(output_files.call.size).to eq(1)
71
74
  end
72
75
 
73
76
  describe 'output response file' do
@@ -76,7 +79,7 @@ describe ResponseMate::Commands::Record do
76
79
  end
77
80
 
78
81
  it 'has the right file extension' do
79
- expect(File.exist?(output_filename)).to be_true
82
+ expect(File.exist?(output_filename)).to be(true)
80
83
  end
81
84
 
82
85
  describe 'YAML content' do
@@ -91,13 +94,9 @@ describe ResponseMate::Commands::Record do
91
94
  expect(subject[:request][:verb]).to be_present
92
95
  end
93
96
 
94
- it 'contains the original request path' do
95
- pending
96
- end
97
+ xit 'contains the original request path'
97
98
 
98
- it 'contains the original request params' do
99
- pending
100
- end
99
+ xit 'contains the original request params'
101
100
 
102
101
  it 'contains the response status' do
103
102
  expect(subject[:response][:status]).