response_mate 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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]).