ruby-resty 0.0.1.pre
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.
- data/.gitignore +22 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/Guardfile +8 -0
- data/README.md +143 -0
- data/Rakefile +24 -0
- data/bin/ruby-resty +7 -0
- data/lib/resty/cli.rb +32 -0
- data/lib/resty/cli_options.rb +75 -0
- data/lib/resty/commands/method_command.rb +30 -0
- data/lib/resty/commands/method_output.rb +41 -0
- data/lib/resty/repl.rb +28 -0
- data/lib/resty/request.rb +57 -0
- data/lib/resty.rb +13 -0
- data/lib/version.rb +3 -0
- data/ruby-resty.gemspec +31 -0
- data/spec/lib/resty/cli_options_spec.rb +102 -0
- data/spec/lib/resty/commands/method_command_spec.rb +72 -0
- data/spec/lib/resty/commands/method_output_spec.rb +59 -0
- data/spec/lib/resty/repl_spec.rb +6 -0
- data/spec/lib/resty/request_spec.rb +89 -0
- data/spec/spec_helper.rb +18 -0
- data/templates/ruby_resty.yml +5 -0
- metadata +269 -0
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
.DS_Store
|
19
|
+
pkg
|
20
|
+
tags
|
21
|
+
.rbenv-version
|
22
|
+
Gemfile.lock
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3@resty --create
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
[](https://travis-ci.org/austenito/ruby-resty)
|
2
|
+
|
3
|
+
# Ruby-Resty
|
4
|
+
|
5
|
+
Ruby-Resty is a ruby port of [Resty][1], which provides a simple way to interact with RESTful services. Ruby-Resty was
|
6
|
+
ported to be shell agnostic and for easier community development.
|
7
|
+
|
8
|
+
The resty REPL is built on top of [Pry][2] for built-in niceties like history, state management, shell interaction,
|
9
|
+
etc.
|
10
|
+
|
11
|
+
# Installation
|
12
|
+
|
13
|
+
```
|
14
|
+
gem install ruby-resty
|
15
|
+
```
|
16
|
+
|
17
|
+
# Supported Ruby Versions
|
18
|
+
|
19
|
+
* Ruby 1.9.3
|
20
|
+
* Ruby 2.0.0
|
21
|
+
|
22
|
+
# Usage
|
23
|
+
|
24
|
+
## The REPL
|
25
|
+
|
26
|
+
To get started, you can enter the REPL by providing the `host` option.
|
27
|
+
|
28
|
+
```
|
29
|
+
ruby-resty --host http://nyan.cat
|
30
|
+
resty>
|
31
|
+
```
|
32
|
+
|
33
|
+
If you would like headers to be attached with every request, you can do so:
|
34
|
+
|
35
|
+
```
|
36
|
+
ruby-resty --host http://nyan.cat --headers X-NYAN-CAT-SECRET-KEY=nyan_nyan X-NYAN-TYPE=octo
|
37
|
+
```
|
38
|
+
|
39
|
+
### REPL Options
|
40
|
+
|
41
|
+
The REPL accepts the following options that are attached to each request. This provides an easier way to make multiple
|
42
|
+
requests without having to specify headers everytime.
|
43
|
+
|
44
|
+
```
|
45
|
+
--alias, -a <s>: The per-host entry to use in ~/.ruby_resty.yml
|
46
|
+
--host, -h: The hostname of the REST service. Ex: http://nyan.cat
|
47
|
+
--headers, -H: The headers attached to each request. Ex: X-NYAN-CAT-SECRET-KEY=nyan_nyan
|
48
|
+
--verbose, -v: Verbose mode
|
49
|
+
--config, -c : Use host information from ~/.ruby_resty.yml
|
50
|
+
```
|
51
|
+
|
52
|
+
### Making Requests
|
53
|
+
|
54
|
+
Requests can be sent to services by specifying a path and any associated JSON data. The following methods are
|
55
|
+
supported:
|
56
|
+
|
57
|
+
```
|
58
|
+
GET [path]
|
59
|
+
PUT [path] [data]
|
60
|
+
POST [path] [data]
|
61
|
+
HEAD [path]
|
62
|
+
DELETE [path]
|
63
|
+
OPTIONS [path]
|
64
|
+
TRACE [path]
|
65
|
+
```
|
66
|
+
|
67
|
+
For example you might want to send a `GET` request, which doesn't require a body:
|
68
|
+
|
69
|
+
```
|
70
|
+
resty> GET /api/cats/1
|
71
|
+
{
|
72
|
+
"nyan_cat": {
|
73
|
+
"name": "octo"
|
74
|
+
"color": "green"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
```
|
78
|
+
|
79
|
+
Or you can send a `POST` request, which does require a body:
|
80
|
+
|
81
|
+
```
|
82
|
+
resty> POST /api/cats '{"nyan_cat": {"name": "oliver", "color": "blue"} }'
|
83
|
+
{
|
84
|
+
"nyan_cat": {
|
85
|
+
"name": "oliver"
|
86
|
+
"color": "blue"
|
87
|
+
}
|
88
|
+
}
|
89
|
+
```
|
90
|
+
|
91
|
+
### REPL Commands
|
92
|
+
|
93
|
+
There are also REPL specific commands ruby-resty is aware of. For example, you can type `exit` to quit the REPL.
|
94
|
+
|
95
|
+
```
|
96
|
+
exit: Quits the REPL
|
97
|
+
```
|
98
|
+
|
99
|
+
## Per Host Configuration
|
100
|
+
|
101
|
+
Including options from the command-line can get tedious, especially if you specify different options to different
|
102
|
+
hosts. The `~/.ruby_resty.yml` config file allows per-host configuration.
|
103
|
+
|
104
|
+
To get started, you can call a generator:
|
105
|
+
|
106
|
+
```
|
107
|
+
rake copy_config
|
108
|
+
```
|
109
|
+
|
110
|
+
This will copy `~/.ruby_resty.yml` which allows you to specify options related to specific hosts.
|
111
|
+
|
112
|
+
```
|
113
|
+
nyan:
|
114
|
+
host: http://nyan.cat
|
115
|
+
headers:
|
116
|
+
header_name: header_value
|
117
|
+
header_name2: header_value2
|
118
|
+
```
|
119
|
+
|
120
|
+
Now instead of starting the REPL like:
|
121
|
+
|
122
|
+
```
|
123
|
+
ruby-resty --host http://nyan.cat --headers header_name=header_value header_name2=header_value2
|
124
|
+
```
|
125
|
+
|
126
|
+
You can omit the header information:
|
127
|
+
|
128
|
+
```
|
129
|
+
ruby-resty --alias nyan
|
130
|
+
```
|
131
|
+
|
132
|
+
# Contributing
|
133
|
+
|
134
|
+
1. Fork it
|
135
|
+
2. Create your feature branch (git checkout -b my-new-feature)
|
136
|
+
3. Commit your changes (git commit -am 'Add some feature')
|
137
|
+
4. Push to the branch (git push origin my-new-feature)
|
138
|
+
5. Create new Pull Request
|
139
|
+
|
140
|
+
Don't forget to run the tests with `rake`
|
141
|
+
|
142
|
+
[1]: https://github.com/micha/resty
|
143
|
+
[2]: https://github.com/pry/pry
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
|
5
|
+
task :default => :spec
|
6
|
+
|
7
|
+
desc "Run specs"
|
8
|
+
task :spec do
|
9
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
10
|
+
t.pattern = './spec/**/*_spec.rb'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Copies an template ruby_resty.yml file to ~/.ruby_resty.yml"
|
15
|
+
task :copy_config do
|
16
|
+
config_file = "#{Dir.home}/.ruby_resty.yml"
|
17
|
+
if File.exist?(config_file)
|
18
|
+
puts "#{config_file} exists. Skipping"
|
19
|
+
else
|
20
|
+
source = "#{Dir.getwd}/templates/ruby_resty.yml"
|
21
|
+
FileUtils.copy(source, config_file)
|
22
|
+
puts "Copied config file to #{config_file}"
|
23
|
+
end
|
24
|
+
end
|
data/bin/ruby-resty
ADDED
data/lib/resty/cli.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'trollop'
|
2
|
+
|
3
|
+
module Resty
|
4
|
+
class Cli
|
5
|
+
|
6
|
+
def run
|
7
|
+
p = Trollop::Parser.new do
|
8
|
+
opt :alias, "The per-host entry to use in ~/.ruby_resty.yml", type: :string, short: "-a"
|
9
|
+
opt :host, "The hostname of the REST service. Ex: http://nyan.cat", type: :string, short: "-h"
|
10
|
+
opt :headers, "The headers sent with each request. Ex: X-NYAN-CAT-SECRET-KEY=nyan_nyan",
|
11
|
+
type: :strings, short: "-H"
|
12
|
+
opt :verbose, "Verbose mode", short: "-v"
|
13
|
+
end
|
14
|
+
|
15
|
+
Trollop::with_standard_exception_handling p do
|
16
|
+
options = p.parse(ARGV)
|
17
|
+
|
18
|
+
if (options[:alias] && options[:host]) || (options[:alias].nil? && options[:host].nil?)
|
19
|
+
puts "Please specify an alias OR a host."
|
20
|
+
raise Trollop::HelpNeeded
|
21
|
+
elsif options.empty?
|
22
|
+
raise Trollop::HelpNeeded
|
23
|
+
end
|
24
|
+
|
25
|
+
Resty::Repl.start(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
rescue ConfigFileError => e
|
29
|
+
puts e.message
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Resty
|
4
|
+
class CliOptions
|
5
|
+
attr_reader :options
|
6
|
+
|
7
|
+
CONFIG_FILE = "#{Dir.home}/.ruby_resty.yml"
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
@options = options
|
11
|
+
|
12
|
+
if options[:headers]
|
13
|
+
parse_command_line_headers
|
14
|
+
elsif host_alias
|
15
|
+
load_config_file
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def host
|
20
|
+
options[:host]
|
21
|
+
end
|
22
|
+
|
23
|
+
def verbose?
|
24
|
+
options[:verbose] ? true : false
|
25
|
+
end
|
26
|
+
|
27
|
+
def host_alias
|
28
|
+
options[:alias]
|
29
|
+
end
|
30
|
+
|
31
|
+
def headers
|
32
|
+
options[:headers] || {}
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def parse_command_line_headers
|
38
|
+
options[:headers] = options[:headers].inject({}) do |hash, header|
|
39
|
+
hash.merge(build_pair(header))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def load_config_file
|
44
|
+
read_config_file.tap do |config|
|
45
|
+
options[:host] = config[host_alias]["host"]
|
46
|
+
options[:headers] = config[host_alias]["headers"]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def read_config_file
|
51
|
+
if File.exist?(CONFIG_FILE)
|
52
|
+
YAML.load_file(CONFIG_FILE).tap { |config| validate_config_entries(config) }
|
53
|
+
else
|
54
|
+
raise ConfigFileError, "#{CONFIG_FILE} is missing."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_config_entries(config)
|
59
|
+
if config[host_alias]
|
60
|
+
unless config[host_alias]["host"]
|
61
|
+
raise ConfigFileError, "Host missing from #{CONFIG_FILE}"
|
62
|
+
end
|
63
|
+
else
|
64
|
+
raise ConfigFileError, "Alias missing from #{CONFIG_FILE}: #{host_alias}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_pair(header)
|
69
|
+
pair = header.split("=")
|
70
|
+
{ pair.first.to_sym => pair.last }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class ConfigFileError < StandardError; end
|
75
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Pry::Commands.create_command /(get|put|post|delete|head|option|patch|trace)/i do
|
2
|
+
description "Echo the input: echo [ARGS]"
|
3
|
+
|
4
|
+
def process
|
5
|
+
params = { method: args[0], path: args[1], data: data(args) }
|
6
|
+
|
7
|
+
Resty::Request.new(cli_options, params).tap do |request|
|
8
|
+
if !request.path_valid?
|
9
|
+
output.puts("A path must be included. Ex: http://nyan.cat/<path>")
|
10
|
+
elsif request.data_required? && !request.data_valid?
|
11
|
+
output.puts("Invalid data. Check if you have valid JSON at: http://jsonlint.com/")
|
12
|
+
else
|
13
|
+
request.send_request do |response, request|
|
14
|
+
method_output = Resty::Commands::MethodOutput.new(cli_options.verbose?, response, request)
|
15
|
+
output.puts(method_output.generate)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def data(args)
|
24
|
+
args[2] ? args[2..-1].join(" ") : ""
|
25
|
+
end
|
26
|
+
|
27
|
+
def cli_options
|
28
|
+
@cli_options ||= eval "self", target
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Resty
|
2
|
+
module Commands
|
3
|
+
class MethodOutput
|
4
|
+
attr_accessor :verbose, :response, :request
|
5
|
+
|
6
|
+
def initialize(verbose, response, request)
|
7
|
+
@verbose = verbose
|
8
|
+
@response = response
|
9
|
+
@request = request
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate
|
13
|
+
output = ""
|
14
|
+
if verbose
|
15
|
+
output += build_line("#{request.method.upcase} #{request.url}")
|
16
|
+
request.processed_headers.each { |key, value| output += build_line("#{key}: #{value}") }
|
17
|
+
output += "\n"
|
18
|
+
|
19
|
+
output += build_line("Response Code: #{response.code}")
|
20
|
+
response.headers.each { |key, value| output += build_line("#{key}: #{value}") }
|
21
|
+
end
|
22
|
+
|
23
|
+
output += pretty_json(response)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def build_line(line)
|
29
|
+
"> #{line}\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
def pretty_json(json)
|
33
|
+
return json if json == ""
|
34
|
+
parsed_json = JSON.parse(json)
|
35
|
+
MultiJson.dump(parsed_json, { pretty: true }) || ""
|
36
|
+
rescue => e
|
37
|
+
""
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/resty/repl.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'readline'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
module Resty
|
5
|
+
class Repl
|
6
|
+
include Readline
|
7
|
+
|
8
|
+
attr_accessor :cli_options, :interrupted
|
9
|
+
|
10
|
+
def initialize(resty_options)
|
11
|
+
@cli_options = Resty::CliOptions.new(resty_options)
|
12
|
+
|
13
|
+
Pry.config.prompt = [ proc { "resty> " }, proc { "*>" }]
|
14
|
+
Pry.config.history.file = "~/.ruby_resty_history"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.start(resty_options)
|
18
|
+
new(resty_options).tap do |repl|
|
19
|
+
Pry.config.input = repl
|
20
|
+
repl.cli_options.pry
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def readline(current_prompt)
|
25
|
+
Readline.readline(current_prompt)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Resty
|
4
|
+
class Request
|
5
|
+
|
6
|
+
attr_accessor :data, :data_valid
|
7
|
+
attr_reader :params, :printer, :cli_options
|
8
|
+
|
9
|
+
def initialize(cli_options, params)
|
10
|
+
@cli_options = cli_options
|
11
|
+
@params = params
|
12
|
+
@data_valid = false
|
13
|
+
load_data
|
14
|
+
end
|
15
|
+
|
16
|
+
def send_request
|
17
|
+
if data_required?
|
18
|
+
RestClient.send(method, url, data, cli_options.headers) { |*params| yield params }
|
19
|
+
else
|
20
|
+
RestClient.send(method, url, cli_options.headers) { |*params| yield params }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def path_valid?
|
25
|
+
path.nil? ? false : true
|
26
|
+
end
|
27
|
+
|
28
|
+
def data_valid?
|
29
|
+
data_valid
|
30
|
+
end
|
31
|
+
|
32
|
+
def data_required?
|
33
|
+
(method =~ %r{put|post|patch}) == 0
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def url
|
39
|
+
"#{cli_options.host}#{path}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def method
|
43
|
+
params[:method]
|
44
|
+
end
|
45
|
+
|
46
|
+
def path
|
47
|
+
params[:path]
|
48
|
+
end
|
49
|
+
|
50
|
+
def load_data
|
51
|
+
self.data = JSON.parse(params[:data]) || {}
|
52
|
+
self.data_valid = true
|
53
|
+
rescue => e
|
54
|
+
self.data = {}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/resty.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'active_support'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
module Resty
|
6
|
+
end
|
7
|
+
|
8
|
+
require_relative "resty/cli"
|
9
|
+
require_relative "resty/cli_options"
|
10
|
+
require_relative "resty/repl"
|
11
|
+
require_relative "resty/request"
|
12
|
+
require_relative "resty/commands/method_command"
|
13
|
+
require_relative "resty/commands/method_output"
|
data/lib/version.rb
ADDED
data/ruby-resty.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require File.expand_path('../lib/version', __FILE__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = 'ruby-resty'
|
7
|
+
gem.version = Resty::VERSION
|
8
|
+
gem.authors = ['Austen Ito']
|
9
|
+
gem.email = ['austen.dev@gmail.com']
|
10
|
+
gem.homepage = ''
|
11
|
+
gem.summary = ''
|
12
|
+
gem.description = gem.summary
|
13
|
+
gem.files = `git ls-files`.split("\n")
|
14
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
gem.require_paths = ['lib']
|
16
|
+
gem.executables << 'ruby-resty'
|
17
|
+
|
18
|
+
gem.add_dependency 'active_support'
|
19
|
+
gem.add_dependency 'pry'
|
20
|
+
gem.add_dependency 'rest-client', '1.6.7'
|
21
|
+
gem.add_dependency 'trollop'
|
22
|
+
gem.add_dependency 'multi_json'
|
23
|
+
|
24
|
+
gem.add_development_dependency 'bourne', "1.4.0"
|
25
|
+
gem.add_development_dependency 'guard'
|
26
|
+
gem.add_development_dependency 'guard-rspec'
|
27
|
+
gem.add_development_dependency 'mocha', "~> 0.13"
|
28
|
+
gem.add_development_dependency 'pry'
|
29
|
+
gem.add_development_dependency 'rspec'
|
30
|
+
gem.add_development_dependency 'rake'
|
31
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Resty::CliOptions do
|
4
|
+
|
5
|
+
context "#host" do
|
6
|
+
let(:options) { Resty::CliOptions.new(host: "foo.com") }
|
7
|
+
|
8
|
+
it "returns host" do
|
9
|
+
expect(options.host).to eq("foo.com")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "#headers" do
|
14
|
+
context "with command-line headers" do
|
15
|
+
let(:options) { Resty::CliOptions.new(host: "foo.com", headers: ["key=star", "type=ninja"],
|
16
|
+
alias: "nyan") }
|
17
|
+
|
18
|
+
it "returns headers" do
|
19
|
+
expect(options.headers).to eq(key: "star", type: "ninja")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "doesn't read config file" do
|
23
|
+
options.should have_received(:load_config_file).never
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "empty headers" do
|
28
|
+
let(:options) { Resty::CliOptions.new({}) }
|
29
|
+
|
30
|
+
it "returns empty hash" do
|
31
|
+
expect(options.headers).to eq({})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "alias" do
|
37
|
+
context "alias exists" do
|
38
|
+
context "headers exist" do
|
39
|
+
before(:each) do
|
40
|
+
YAML.stubs(:load_file).returns({"nyan" => { "host" => "nyan.cat",
|
41
|
+
"headers" => { "header" => "value" } } })
|
42
|
+
File.stubs(:exist?).returns(true)
|
43
|
+
@options = Resty::CliOptions.new(alias: "nyan")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "returns host" do
|
47
|
+
expect(@options.host).to eq("nyan.cat")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "returns headers" do
|
51
|
+
expect(@options.headers).to eq("header" => "value")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "loads YAML file" do
|
55
|
+
YAML.should have_received(:load_file).with("#{Dir.home}/.ruby_resty.yml")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "headers don't exist" do
|
61
|
+
before(:each) do
|
62
|
+
YAML.stubs(:load_file).returns({"nyan" => { "host" => "nyan.cat" } } )
|
63
|
+
File.stubs(:exist?).returns(true)
|
64
|
+
@options = Resty::CliOptions.new(alias: "nyan")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "returns host" do
|
68
|
+
expect(@options.host).to eq("nyan.cat")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns headers" do
|
72
|
+
expect(@options.headers).to eq({})
|
73
|
+
end
|
74
|
+
|
75
|
+
it "loads YAML file" do
|
76
|
+
YAML.should have_received(:load_file).with("#{Dir.home}/.ruby_resty.yml")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "config file doesn't exist" do
|
81
|
+
it "raises ConfigFileError" do
|
82
|
+
File.stubs(:exist?).returns(false)
|
83
|
+
expect { Resty::CliOptions.new(alias: "nyan") }.to raise_error(Resty::ConfigFileError)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "alias doesn't exist" do
|
88
|
+
it "raises ConfigFileError" do
|
89
|
+
File.stubs(:exist?).returns(true)
|
90
|
+
expect { Resty::CliOptions.new(alias: "nyan") }.to raise_error(Resty::ConfigFileError)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "host doesn't exist" do
|
95
|
+
it "raises error" do
|
96
|
+
YAML.stubs(:load_file).returns({"nyan" => {}})
|
97
|
+
File.stubs(:exist?).returns(true)
|
98
|
+
expect { Resty::CliOptions.new(alias: "nyan") }.to raise_error(Resty::ConfigFileError)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
describe "MethodCommand" do
|
5
|
+
before(:each) do
|
6
|
+
Resty::Request.stubs(:new).returns(request)
|
7
|
+
end
|
8
|
+
|
9
|
+
context "command regex" do
|
10
|
+
let(:request) { stub(path_valid?: false) }
|
11
|
+
|
12
|
+
it "responds lower case method" do
|
13
|
+
%w{get put post delete head option patch trace}.each do |method|
|
14
|
+
pry_eval(method)
|
15
|
+
end
|
16
|
+
Resty::Request.should have_received(:new).times(8)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "responds to case-insentivity" do
|
20
|
+
%w{GET Put PoSt delete head option patch trace}.each do |method|
|
21
|
+
pry_eval(method)
|
22
|
+
end
|
23
|
+
Resty::Request.should have_received(:new).times(8)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "process" do
|
28
|
+
context "invalid path" do
|
29
|
+
let(:request) { stub(path_valid?: false) }
|
30
|
+
|
31
|
+
it "doesn't send request" do
|
32
|
+
pry_eval("get")
|
33
|
+
request.should have_received(:send_request).never
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "invalid data" do
|
38
|
+
let(:request) { stub(path_valid?: :true, data_valid?: false, data_required?: true) }
|
39
|
+
|
40
|
+
it "doesn't send request" do
|
41
|
+
pry_eval("get")
|
42
|
+
request.should have_received(:send_request).never
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "valid arguments" do
|
47
|
+
let(:response) { stub }
|
48
|
+
let(:request) { stub(path_valid?: :true, data_valid?: true, data_required?: true) }
|
49
|
+
let(:params) { { method: "get", path: "/api/nyan", data: "#{JSON.dump(foo: 'bar')}"} }
|
50
|
+
let(:method_output) { stub(generate: "")}
|
51
|
+
|
52
|
+
before(:each) do
|
53
|
+
Resty::Commands::MethodOutput.stubs(:new).returns(method_output)
|
54
|
+
Object.any_instance.stubs(:verbose?).returns(false)
|
55
|
+
request.stubs(:send_request).yields(response, request)
|
56
|
+
pry_eval("get /api/nyan '#{JSON.dump(foo: 'bar')}'")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "creates request" do
|
60
|
+
Resty::Request.should have_received(:new).with(anything, params)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "sends request" do
|
64
|
+
Resty::Commands::MethodOutput.should have_received(:new).with(false, response,request)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "generates output" do
|
68
|
+
method_output.should have_received(:generate)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
describe Resty::Commands::MethodOutput do
|
5
|
+
let(:request) { stub }
|
6
|
+
let(:response) { JSON.dump({foo: "bar"}) }
|
7
|
+
|
8
|
+
context "#print" do
|
9
|
+
it "returns empty string with no json output" do
|
10
|
+
method_output = Resty::Commands::MethodOutput.new(false, "", request)
|
11
|
+
method_output.generate.should eq("")
|
12
|
+
end
|
13
|
+
|
14
|
+
context "non-verbose" do
|
15
|
+
let(:method_output) { Resty::Commands::MethodOutput.new(false, response, request) }
|
16
|
+
|
17
|
+
it "returns output" do
|
18
|
+
output = <<-eos.unindent
|
19
|
+
{
|
20
|
+
"foo": "bar"
|
21
|
+
}
|
22
|
+
eos
|
23
|
+
|
24
|
+
# multi-line text adds an extra \n, so let's ignore it
|
25
|
+
method_output.generate.should eq(output[0..-2])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "verbose" do
|
30
|
+
let(:method_output) { Resty::Commands::MethodOutput.new(true, response, request) }
|
31
|
+
|
32
|
+
before(:each) do
|
33
|
+
request.stubs(:method).returns("get")
|
34
|
+
request.stubs(:url).returns("foo.com")
|
35
|
+
request.stubs(:processed_headers).returns(header: "value", header2: "value2")
|
36
|
+
response.stubs(:code).returns(200)
|
37
|
+
response.stubs(:headers).returns(response_header: "value", response_header2: "value2")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns verbose output" do
|
41
|
+
output = <<-eos.unindent
|
42
|
+
> GET foo.com
|
43
|
+
> header: value
|
44
|
+
> header2: value2
|
45
|
+
|
46
|
+
> Response Code: 200
|
47
|
+
> response_header: value
|
48
|
+
> response_header2: value2
|
49
|
+
{
|
50
|
+
"foo": "bar"
|
51
|
+
}
|
52
|
+
eos
|
53
|
+
|
54
|
+
# multi-line text adds an extra \n, so let's ignore it
|
55
|
+
method_output.generate.should eq(output[0..-2])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Resty::Request do
|
4
|
+
let(:cli_options) { stub(host: "foo.com", verbose?: false, headers: { header: "value" }) }
|
5
|
+
|
6
|
+
context "#send_request" do
|
7
|
+
before(:each) do
|
8
|
+
RestClient.stubs(:send)
|
9
|
+
end
|
10
|
+
|
11
|
+
context "GET" do
|
12
|
+
let(:params) { { method: "get", path: "/api/merchants" } }
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
Resty::Request.new(cli_options, params).send_request
|
16
|
+
end
|
17
|
+
|
18
|
+
it "sends request" do
|
19
|
+
RestClient.should have_received(:send).with("get", "foo.com/api/merchants",
|
20
|
+
{header: "value"})
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "DELETE" do
|
25
|
+
let(:params) { { method: "delete", path: "/api/merchants" } }
|
26
|
+
|
27
|
+
before(:each) do
|
28
|
+
Resty::Request.new(cli_options, params).send_request
|
29
|
+
end
|
30
|
+
|
31
|
+
it "sends request" do
|
32
|
+
RestClient.should have_received(:send).with("delete", "foo.com/api/merchants",
|
33
|
+
{header: "value"})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "HEAD" do
|
38
|
+
let(:params) { { method: "head", path: "/api/merchants" } }
|
39
|
+
|
40
|
+
before(:each) do
|
41
|
+
Resty::Request.new(cli_options, params).send_request
|
42
|
+
end
|
43
|
+
|
44
|
+
it "sends request" do
|
45
|
+
RestClient.should have_received(:send).with("head", "foo.com/api/merchants",
|
46
|
+
{header: "value"})
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "OPTIONS" do
|
51
|
+
let(:params) { { method: "options", path: "/api/merchants" } }
|
52
|
+
|
53
|
+
before(:each) do
|
54
|
+
Resty::Request.new(cli_options, params).send_request
|
55
|
+
end
|
56
|
+
|
57
|
+
it "sends request" do
|
58
|
+
RestClient.should have_received(:send).with("options", "foo.com/api/merchants",
|
59
|
+
{header: "value"})
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "PUT" do
|
64
|
+
let(:params) { { method: "put", path: "/api/merchants", data: JSON.dump(foo: "bar") } }
|
65
|
+
|
66
|
+
before(:each) do
|
67
|
+
Resty::Request.new(cli_options, params).send_request
|
68
|
+
end
|
69
|
+
|
70
|
+
it "sends request" do
|
71
|
+
RestClient.should have_received(:send).with("put", "foo.com/api/merchants",
|
72
|
+
{"foo" => "bar"}, {header: "value"})
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "POST" do
|
77
|
+
let(:params) { { method: "post", path: "/api/merchants", data: JSON.dump(foo: "bar") } }
|
78
|
+
|
79
|
+
before(:each) do
|
80
|
+
Resty::Request.new(cli_options, params).send_request
|
81
|
+
end
|
82
|
+
|
83
|
+
it "sends request" do
|
84
|
+
RestClient.should have_received(:send).with("post", "foo.com/api/merchants",
|
85
|
+
{"foo" => "bar"}, {header: "value"})
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative "../lib/resty"
|
2
|
+
|
3
|
+
require 'mocha/api'
|
4
|
+
require 'bourne'
|
5
|
+
|
6
|
+
require 'pry/test/helper'
|
7
|
+
|
8
|
+
RSpec.configure do |c|
|
9
|
+
c.mock_with :mocha
|
10
|
+
|
11
|
+
include PryTestHelpers
|
12
|
+
end
|
13
|
+
|
14
|
+
class String
|
15
|
+
def unindent
|
16
|
+
gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, "")
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,269 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-resty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.pre
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Austen Ito
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: active_support
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: pry
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rest-client
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.6.7
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.6.7
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: trollop
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: multi_json
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: bourne
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - '='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.4.0
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - '='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.4.0
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: guard
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: guard-rspec
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: mocha
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0.13'
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0.13'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: pry
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: rspec
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ! '>='
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
type: :development
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ! '>='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
- !ruby/object:Gem::Dependency
|
191
|
+
name: rake
|
192
|
+
requirement: !ruby/object:Gem::Requirement
|
193
|
+
none: false
|
194
|
+
requirements:
|
195
|
+
- - ! '>='
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0'
|
198
|
+
type: :development
|
199
|
+
prerelease: false
|
200
|
+
version_requirements: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - ! '>='
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
206
|
+
description: ''
|
207
|
+
email:
|
208
|
+
- austen.dev@gmail.com
|
209
|
+
executables:
|
210
|
+
- ruby-resty
|
211
|
+
extensions: []
|
212
|
+
extra_rdoc_files: []
|
213
|
+
files:
|
214
|
+
- .gitignore
|
215
|
+
- .rspec
|
216
|
+
- .rvmrc
|
217
|
+
- .travis.yml
|
218
|
+
- Gemfile
|
219
|
+
- Guardfile
|
220
|
+
- README.md
|
221
|
+
- Rakefile
|
222
|
+
- bin/ruby-resty
|
223
|
+
- lib/resty.rb
|
224
|
+
- lib/resty/cli.rb
|
225
|
+
- lib/resty/cli_options.rb
|
226
|
+
- lib/resty/commands/method_command.rb
|
227
|
+
- lib/resty/commands/method_output.rb
|
228
|
+
- lib/resty/repl.rb
|
229
|
+
- lib/resty/request.rb
|
230
|
+
- lib/version.rb
|
231
|
+
- ruby-resty.gemspec
|
232
|
+
- spec/lib/resty/cli_options_spec.rb
|
233
|
+
- spec/lib/resty/commands/method_command_spec.rb
|
234
|
+
- spec/lib/resty/commands/method_output_spec.rb
|
235
|
+
- spec/lib/resty/repl_spec.rb
|
236
|
+
- spec/lib/resty/request_spec.rb
|
237
|
+
- spec/spec_helper.rb
|
238
|
+
- templates/ruby_resty.yml
|
239
|
+
homepage: ''
|
240
|
+
licenses: []
|
241
|
+
post_install_message:
|
242
|
+
rdoc_options: []
|
243
|
+
require_paths:
|
244
|
+
- lib
|
245
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
246
|
+
none: false
|
247
|
+
requirements:
|
248
|
+
- - ! '>='
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: '0'
|
251
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
252
|
+
none: false
|
253
|
+
requirements:
|
254
|
+
- - ! '>'
|
255
|
+
- !ruby/object:Gem::Version
|
256
|
+
version: 1.3.1
|
257
|
+
requirements: []
|
258
|
+
rubyforge_project:
|
259
|
+
rubygems_version: 1.8.24
|
260
|
+
signing_key:
|
261
|
+
specification_version: 3
|
262
|
+
summary: ''
|
263
|
+
test_files:
|
264
|
+
- spec/lib/resty/cli_options_spec.rb
|
265
|
+
- spec/lib/resty/commands/method_command_spec.rb
|
266
|
+
- spec/lib/resty/commands/method_output_spec.rb
|
267
|
+
- spec/lib/resty/repl_spec.rb
|
268
|
+
- spec/lib/resty/request_spec.rb
|
269
|
+
- spec/spec_helper.rb
|