restfully 0.8.8 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +37 -2
- data/bin/restfully +123 -73
- data/lib/restfully.rb +2 -0
- data/lib/restfully/configuration.rb +64 -0
- data/lib/restfully/session.rb +26 -30
- data/lib/restfully/version.rb +1 -1
- data/spec/fixtures/config.yml +5 -0
- data/spec/restfully/configuration_spec.rb +45 -0
- data/spec/restfully/session_spec.rb +11 -6
- metadata +86 -28
data/README.md
CHANGED
@@ -16,6 +16,9 @@ Therefore, Restfully can work with any reasonably RESTful API provided that:
|
|
16
16
|
|
17
17
|
If one of the API `Content-Type` is not already supported by one of the `Restfully::MediaType` objects (see `lib/restfully/media_type`), then you just have to build it and register it with Restfully.
|
18
18
|
|
19
|
+
Documentation can be found at <http://rubydoc.info/gems/restfully>.
|
20
|
+
|
21
|
+
|
19
22
|
## Installation
|
20
23
|
|
21
24
|
$ gem install restfully
|
@@ -24,16 +27,17 @@ If you require media-types that need an XML parser, you must also install the `l
|
|
24
27
|
|
25
28
|
$ gem install libxml-ruby
|
26
29
|
|
30
|
+
|
27
31
|
## Usage
|
28
32
|
|
29
33
|
### Command line
|
30
34
|
|
31
35
|
$ export RUBYOPT="-rubygems"
|
32
|
-
$ restfully URI [-u username] [-p password]
|
36
|
+
$ restfully --uri URI [-u username] [-p password]
|
33
37
|
|
34
38
|
e.g., for the [Grid'5000 API](https://www.grid5000.fr/mediawiki/index.php/API):
|
35
39
|
|
36
|
-
$ restfully https://api.grid5000.fr/sid/grid5000 -u username -p password
|
40
|
+
$ restfully --uri https://api.grid5000.fr/sid/grid5000 -u username -p password
|
37
41
|
|
38
42
|
If the connection was successful, you should get a prompt. You may enter:
|
39
43
|
|
@@ -81,9 +85,39 @@ And then:
|
|
81
85
|
|
82
86
|
$ restfully -c ~/.restfully/api.grid5000.fr.yml
|
83
87
|
|
88
|
+
If you want to record the commands you enter in your interactive session, just
|
89
|
+
add the `--record` flag, and at the end of your session the commands you
|
90
|
+
entered will have been written into `SESSION_FILE` (by default:
|
91
|
+
`restfully-tape`).
|
92
|
+
|
93
|
+
### Replay
|
94
|
+
|
95
|
+
Restfully can replay a sequence of ruby expressions. Just pass the FILE (local
|
96
|
+
or HTTP URI) as argument to the `restfully` tool:
|
97
|
+
|
98
|
+
$ restfully -c ~/.restfully/my-config.yml path/to/file.rb
|
99
|
+
$ restfully -c ~/.restfully/my-config.yml http://server.ltd/script.rb
|
100
|
+
|
101
|
+
Or via STDIN:
|
102
|
+
|
103
|
+
$ echo "pp root" | restfully -c ~/.restfully/config.yml
|
104
|
+
|
105
|
+
Don't hesitate to play with the `--replay` option, which outputs the content of the FILE line by line, and the result of each expression.
|
106
|
+
|
107
|
+
By default, the program exits when the content of the FILE has been executed.
|
108
|
+
Pass the `--shell` flag to keep a shell open in the same Restfully session
|
109
|
+
after FILE has been executed. This is useful if you want to manipulate the
|
110
|
+
variables defined by the FILE.
|
111
|
+
|
112
|
+
Also, note that any `Restfully::Session.new(...)` declaration in the code you
|
113
|
+
execute will have its configuration overridden with anything given on the
|
114
|
+
command line (either in a configuration file or as arguments). Therefore you
|
115
|
+
can easily execute scripts written by others, in your own context.
|
116
|
+
|
84
117
|
### As a library
|
85
118
|
See the `examples` directory for examples.
|
86
119
|
|
120
|
+
|
87
121
|
## Development
|
88
122
|
|
89
123
|
### Testing
|
@@ -99,6 +133,7 @@ See the `examples` directory for examples.
|
|
99
133
|
* Commit, do not mess with Rakefile, version, or history (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull).
|
100
134
|
* Send me a pull request.
|
101
135
|
|
136
|
+
|
102
137
|
## Copyright
|
103
138
|
|
104
139
|
Copyright (c) 2009-2011 [Cyril Rohr](http://crohr.me), INRIA Rennes - Bretagne Atlantique.
|
data/bin/restfully
CHANGED
@@ -5,120 +5,170 @@ require 'restfully'
|
|
5
5
|
require 'optparse'
|
6
6
|
require 'logger'
|
7
7
|
require 'pp'
|
8
|
+
require 'ripl'
|
9
|
+
require 'ripl/multi_line'
|
8
10
|
|
9
11
|
# Behaviour of pp in IRB is different on ruby1.9:
|
10
12
|
# * pp(object) returns object#inspect.
|
11
13
|
# * we prefer the behaviour of ruby1.8 where pp returns nil.
|
12
|
-
alias :old_pp :pp
|
14
|
+
alias :old_pp :pp
|
13
15
|
def pp(*args)
|
14
16
|
old_pp(*args); nil
|
15
17
|
end
|
16
18
|
|
17
19
|
logger = Logger.new(STDERR)
|
18
20
|
logger.level = Logger::WARN
|
19
|
-
|
21
|
+
|
22
|
+
OPTIONS = {"logger" => logger, "shell" => false}
|
23
|
+
|
24
|
+
Ripl.config[:play_quiet] = true
|
25
|
+
Ripl.config[:play_input] = false
|
20
26
|
|
21
27
|
option_parser = OptionParser.new do |opts|
|
22
28
|
opts.banner = <<BANNER
|
23
29
|
* Description
|
24
30
|
Restfully #{Restfully::VERSION} - Access REST APIs effortlessly
|
25
31
|
* Usage
|
26
|
-
restfully [
|
27
|
-
|
32
|
+
restfully [options] [FILE]
|
33
|
+
|
34
|
+
If FILE is given and is an HTTP URI or a local file, the content of that file will be executed in the context of the Restfully session. It can also be read from STDIN.
|
35
|
+
If no FILE is given, then an interactive shell will be launched in the context of the Restfully session.
|
28
36
|
BANNER
|
29
37
|
|
30
|
-
opts.
|
31
|
-
|
38
|
+
opts.separator ""
|
39
|
+
opts.separator "* Common options"
|
40
|
+
opts.on("--uri=", "Sets the base URI") do |v|
|
41
|
+
OPTIONS["uri"] = v
|
42
|
+
end
|
43
|
+
opts.on("-u=", "--username=", "Sets the username (Basic Authentication)") do |u|
|
44
|
+
OPTIONS["username"] = u
|
32
45
|
end
|
33
|
-
opts.on("-p=", "--password=", "Sets the
|
34
|
-
|
46
|
+
opts.on("-p=", "--password=", "Sets the password (Basic Authentication)") do |p|
|
47
|
+
OPTIONS["password"] = p
|
35
48
|
end
|
36
|
-
opts.on("-c=", "--config=", "
|
37
|
-
|
49
|
+
opts.on("-c=", "--config=", "Load options from a custom YAML configuration file") do |v|
|
50
|
+
OPTIONS["configuration_file"] = v
|
38
51
|
end
|
39
52
|
opts.on("-r=", "--require=", "Require an additional media-type") do |v|
|
40
|
-
|
41
|
-
|
53
|
+
OPTIONS["require"] ||= []
|
54
|
+
OPTIONS["require"].push(v)
|
42
55
|
end
|
43
|
-
opts.on("--log=", "Outputs log messages to the given file. Defaults to
|
56
|
+
opts.on("--log=", "Outputs log messages to the given file. Defaults to STDERR") do |v|
|
44
57
|
original_logger_level = logger.level
|
45
|
-
|
58
|
+
@log_file = File.open(File.expand_path(v), "w+")
|
59
|
+
STDERR.sync = true
|
60
|
+
STDERR.reopen(@log_file)
|
61
|
+
logger = Logger.new(@log_file)
|
46
62
|
logger.level = original_logger_level
|
47
|
-
|
63
|
+
OPTIONS["logger"] = logger
|
48
64
|
end
|
49
65
|
opts.on("--no-cache", "Disable client-side caching") do |v|
|
50
|
-
|
66
|
+
OPTIONS["cache"] = false
|
67
|
+
end
|
68
|
+
opts.on("--color", "Color output") do |v|
|
69
|
+
require 'ripl/color_streams'
|
70
|
+
require 'ripl/color_result'
|
71
|
+
end
|
72
|
+
opts.on("--record [SESSION_FILE]", "Record interactive session into SESSION_FILE (default=#{Restfully::DEFAULT_TAPE}), to be replayed later. This option is ignored if FILE is given.") do |v|
|
73
|
+
OPTIONS["record"] = v || Restfully::DEFAULT_TAPE
|
51
74
|
end
|
52
75
|
opts.on("-v", "--verbose", "Run verbosely") do |v|
|
53
|
-
|
76
|
+
OPTIONS["logger"].level = Logger::INFO
|
54
77
|
end
|
55
78
|
opts.on("--debug", "Run in debug mode") do |v|
|
56
|
-
|
79
|
+
OPTIONS["logger"].level = Logger::DEBUG
|
80
|
+
end
|
81
|
+
|
82
|
+
opts.separator ""
|
83
|
+
opts.separator "* Options specific to FILE"
|
84
|
+
opts.on("--replay", "Display the FILE input line by line, and the result of each command") do |v|
|
85
|
+
Ripl.config[:play_input] = true
|
86
|
+
Ripl.config[:play_quiet] = false
|
57
87
|
end
|
88
|
+
opts.on("--shell", "Start an interactive session even after FILE content has been executed") do |v|
|
89
|
+
OPTIONS["shell"] = true
|
90
|
+
end
|
91
|
+
opts.on("-i", "--install", "Ask to install any gem that might be required in FILE") do |v|
|
92
|
+
Ripl.config[:play_install] = true
|
93
|
+
end
|
94
|
+
|
95
|
+
opts.separator ""
|
96
|
+
opts.separator "* Other"
|
58
97
|
opts.on_tail("-h", "--help", "Show this message") do
|
59
98
|
puts opts
|
60
99
|
exit
|
61
100
|
end
|
101
|
+
opts.on_tail("--version", "Show version") do
|
102
|
+
puts Restfully::VERSION
|
103
|
+
exit
|
104
|
+
end
|
105
|
+
end.parse!
|
106
|
+
|
107
|
+
# Declare original Restfully::Session
|
108
|
+
@session = Restfully::Session.new(OPTIONS)
|
109
|
+
|
110
|
+
if $stdin.tty? && !ARGV[0]
|
111
|
+
# Interactive session
|
112
|
+
puts "Restfully/#{Restfully::VERSION} - The root resource is available in the 'root' variable."
|
113
|
+
if OPTIONS["record"]
|
114
|
+
# Recording requested
|
115
|
+
require 'ripl/record'
|
116
|
+
Ripl.config[:play] = OPTIONS["record"]
|
117
|
+
end
|
118
|
+
else
|
119
|
+
# Replayed session
|
120
|
+
@session.logger.warn "--record option valid only with interactive session. Ignoring." if OPTIONS["record"]
|
121
|
+
require 'ripl/play'
|
122
|
+
|
123
|
+
module Ripl::Play
|
124
|
+
# Overwrite #get_input so that it does not display the input if not
|
125
|
+
# required.
|
126
|
+
def get_input
|
127
|
+
puts(prompt + @play_input) if Ripl.config[:play_input]
|
128
|
+
@play_input
|
129
|
+
end
|
130
|
+
end
|
62
131
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
require 'irb'
|
82
|
-
require 'irb/completion'
|
83
|
-
require 'irb/ext/save-history'
|
84
|
-
|
85
|
-
HOME = ENV['HOME'] || ENV['HOMEPATH']
|
86
|
-
# Keep history of your last commands.
|
87
|
-
# Taken from <http://blog.nicksieger.com/articles/2006/04/23/tweaking-irb>
|
88
|
-
IRB.conf[:SAVE_HISTORY] = 100
|
89
|
-
IRB.conf[:HISTORY_FILE] = "#{HOME}/.irb-save-history"
|
90
|
-
|
91
|
-
# Raises an error on Windows, so disabling it.
|
92
|
-
if RUBY_PLATFORM !~ /(win|w)32$/
|
93
|
-
module Readline
|
94
|
-
module History
|
95
|
-
LOG = "#{HOME}/.irb-history"
|
96
|
-
|
97
|
-
def self.write_log(line)
|
98
|
-
File.open(LOG, 'ab') {|f|
|
99
|
-
f << "#{line}\n"
|
100
|
-
}
|
101
|
-
end
|
102
|
-
|
103
|
-
def self.start_session_log
|
104
|
-
write_log("\n")
|
105
|
-
end
|
132
|
+
module Ripl::PlayWithoutWhitespace
|
133
|
+
# Remove empty lines when replaying
|
134
|
+
def play_back_string(str)
|
135
|
+
str.gsub!(/^\s*\n+/, '')
|
136
|
+
super(str)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
Ripl::Shell.include Ripl::PlayWithoutWhitespace
|
140
|
+
|
141
|
+
unless OPTIONS["shell"]
|
142
|
+
# Use readline-rb to avoid error message 'Bond has detected EditLine and
|
143
|
+
# may not work with it. See the README's Limitations section.' when no
|
144
|
+
# shell is requested after execution of FILE.
|
145
|
+
Ripl.config[:readline] = 'readline-rb'
|
146
|
+
Ripl.config[:completion] = {:readline => :ruby }
|
147
|
+
module Ripl::Exit
|
148
|
+
def before_loop; super; exit; end
|
106
149
|
end
|
150
|
+
Ripl::Shell.include Ripl::Exit
|
151
|
+
end
|
152
|
+
|
153
|
+
Ripl.config[:play] = ARGV[0].dup if ARGV[0]
|
154
|
+
end
|
107
155
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
156
|
+
module Restfully
|
157
|
+
class Session
|
158
|
+
alias :old_initialize :initialize
|
159
|
+
# Overwrite Restfully::Session.new calls that might occur in replayed
|
160
|
+
# scripts, so that they preferably take the configuration given with the
|
161
|
+
# restfully command-line tool.
|
162
|
+
def initialize(options = {}, &block)
|
163
|
+
old_opts = Configuration.new(options).expand
|
164
|
+
new_opts = Configuration.new(OPTIONS).expand
|
165
|
+
old_initialize(old_opts.merge(new_opts).to_hash, &block)
|
116
166
|
end
|
117
167
|
end
|
118
|
-
Readline::History.start_session_log
|
119
168
|
end
|
120
169
|
|
170
|
+
# Ensure to close the log file, if any, when exiting.
|
171
|
+
at_exit{ @log_file && @log_file.close }
|
172
|
+
|
121
173
|
ARGV.clear
|
122
|
-
|
123
|
-
IRB.start
|
124
|
-
exit!
|
174
|
+
Ripl.start :binding => @session.instance_eval{ binding }
|
data/lib/restfully.rb
CHANGED
@@ -2,6 +2,7 @@ require 'backports'
|
|
2
2
|
require 'yaml'
|
3
3
|
|
4
4
|
require 'restfully/version'
|
5
|
+
require 'restfully/configuration'
|
5
6
|
require 'restfully/error'
|
6
7
|
require 'restfully/http'
|
7
8
|
require 'restfully/link'
|
@@ -12,6 +13,7 @@ require 'restfully/session'
|
|
12
13
|
require 'restfully/media_type'
|
13
14
|
|
14
15
|
module Restfully
|
16
|
+
DEFAULT_TAPE = "restfully-tape"
|
15
17
|
# Include the default media-types
|
16
18
|
MediaType.reset
|
17
19
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Restfully
|
4
|
+
class Configuration
|
5
|
+
attr_reader :options
|
6
|
+
|
7
|
+
def initialize(opts = {})
|
8
|
+
@options = opts.symbolize_keys
|
9
|
+
end
|
10
|
+
|
11
|
+
def merge(config = {})
|
12
|
+
if config.respond_to?(:to_hash)
|
13
|
+
@options.merge!(config.to_hash.symbolize_keys) do |key, oldval, newval|
|
14
|
+
case oldval
|
15
|
+
when Array then oldval.push(newval).flatten.uniq
|
16
|
+
when Hash then oldval.merge(newval)
|
17
|
+
else newval
|
18
|
+
end
|
19
|
+
end
|
20
|
+
self
|
21
|
+
else
|
22
|
+
raise ArgumentError, "Don't know how to merge #{config.class}."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_hash
|
27
|
+
@options
|
28
|
+
end
|
29
|
+
|
30
|
+
# Attempt to expand the configuration if a :configuration_file options is
|
31
|
+
# present. Existing options take precedence over those defined in the
|
32
|
+
# configuration file.
|
33
|
+
def expand
|
34
|
+
file = ENV['RESTFULLY_CONFIG'] || @options[:configuration_file]
|
35
|
+
if file
|
36
|
+
file = File.expand_path(file)
|
37
|
+
if File.file?(file) && File.readable?(file)
|
38
|
+
@options = self.class.load(file).merge(self).options
|
39
|
+
end
|
40
|
+
end
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def [](key)
|
45
|
+
@options[key.to_sym]
|
46
|
+
end
|
47
|
+
|
48
|
+
def []=(key, value)
|
49
|
+
@options[key.to_sym] = value
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete(key)
|
53
|
+
@options.delete(key.to_sym)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.load(file)
|
57
|
+
if file.nil?
|
58
|
+
raise ArgumentError, "file can't be nil"
|
59
|
+
else
|
60
|
+
new(YAML.load_file(File.expand_path(file)))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/restfully/session.rb
CHANGED
@@ -11,9 +11,18 @@ module Restfully
|
|
11
11
|
class Session
|
12
12
|
|
13
13
|
|
14
|
-
|
14
|
+
attr_writer :logger
|
15
|
+
attr_accessor :uri
|
15
16
|
attr_reader :config
|
16
17
|
attr_writer :default_headers
|
18
|
+
|
19
|
+
def logger
|
20
|
+
@logger ||= begin
|
21
|
+
l = Logger.new(STDERR)
|
22
|
+
l.level = Logger::INFO
|
23
|
+
l
|
24
|
+
end
|
25
|
+
end
|
17
26
|
|
18
27
|
# Builds a new client session.
|
19
28
|
# Takes a number of <tt>options</tt> as input.
|
@@ -27,7 +36,7 @@ module Restfully
|
|
27
36
|
# <tt>:wait_before_retry</tt>:: the number of seconds to wait before making another attempt when a server or connection error occurs.
|
28
37
|
# <tt>:default_headers</tt>:: a Hash of default HTTP headers to send with each request.
|
29
38
|
# <tt>:cache</tt>:: a Hash of parameters to configure the caching component. See <http://rtomayko.github.com/rack-cache/configuration> for more information.
|
30
|
-
#
|
39
|
+
#
|
31
40
|
# e.g.
|
32
41
|
# Restfully::Session.new(
|
33
42
|
# :uri => "https://api.bonfire-project.eu:444/",
|
@@ -37,26 +46,8 @@ module Restfully
|
|
37
46
|
# ) {|root, session| p root}
|
38
47
|
#
|
39
48
|
def initialize(options = {})
|
40
|
-
@config = options.
|
49
|
+
@config = Configuration.new(options).expand
|
41
50
|
@logger = @config.delete(:logger)
|
42
|
-
if @logger.nil?
|
43
|
-
@logger = Logger.new(STDERR)
|
44
|
-
@logger.level = Logger::INFO
|
45
|
-
end
|
46
|
-
|
47
|
-
# Read configuration from file:
|
48
|
-
config_file = ENV['RESTFULLY_CONFIG'] || @config.delete(:configuration_file)
|
49
|
-
config_file = File.expand_path(config_file) if config_file
|
50
|
-
if config_file && File.file?(config_file) && File.readable?(config_file)
|
51
|
-
@logger.info "Using configuration file located at #{config_file}."
|
52
|
-
@config = YAML.load_file(config_file).symbolize_keys.merge(@config) do |key, oldval, newval|
|
53
|
-
case oldval
|
54
|
-
when Array then oldval.push(newval).flatten
|
55
|
-
when Hash then oldval.merge(newval)
|
56
|
-
else newval
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
51
|
|
61
52
|
@config[:retry_on_error] ||= 5
|
62
53
|
@config[:wait_before_retry] ||= 5
|
@@ -77,7 +68,7 @@ module Restfully
|
|
77
68
|
|
78
69
|
# Require additional types (e.g.: media-types):
|
79
70
|
(@config[:require] || []).each do |r|
|
80
|
-
|
71
|
+
logger.info "Requiring #{r}..."
|
81
72
|
if ::File.exist?(file=File.expand_path(r))
|
82
73
|
require file
|
83
74
|
elsif r =~ /^https?:\/\//i
|
@@ -146,6 +137,11 @@ module Restfully
|
|
146
137
|
get(uri.path).load
|
147
138
|
end
|
148
139
|
|
140
|
+
# Returns self.
|
141
|
+
def session
|
142
|
+
self
|
143
|
+
end
|
144
|
+
|
149
145
|
# Returns an HTTP::Response object or raise a Restfully::HTTP::Error
|
150
146
|
def head(path, options = {})
|
151
147
|
transmit :head, path, options
|
@@ -173,14 +169,6 @@ module Restfully
|
|
173
169
|
transmit :delete, path, options
|
174
170
|
end
|
175
171
|
|
176
|
-
# Build and execute the corresponding HTTP request,
|
177
|
-
# then process the response.
|
178
|
-
def transmit(method, path, options)
|
179
|
-
request = HTTP::Request.new(self, method, path, options)
|
180
|
-
response = request.execute!
|
181
|
-
process(response, request)
|
182
|
-
end
|
183
|
-
|
184
172
|
# Process a Restfully::HTTP::Response.
|
185
173
|
def process(response, request)
|
186
174
|
case code=response.code
|
@@ -208,6 +196,14 @@ module Restfully
|
|
208
196
|
end
|
209
197
|
|
210
198
|
protected
|
199
|
+
# Build and execute the corresponding HTTP request,
|
200
|
+
# then process the response.
|
201
|
+
def transmit(method, path, options)
|
202
|
+
request = HTTP::Request.new(self, method, path, options)
|
203
|
+
response = request.execute!
|
204
|
+
process(response, request)
|
205
|
+
end
|
206
|
+
|
211
207
|
def setup_cache(options = {})
|
212
208
|
return if options == false
|
213
209
|
opts = {:verbose => (logger.level <= Logger::INFO)}.merge(
|
data/lib/restfully/version.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Restfully::Configuration do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@config_file = File.expand_path("../../fixtures/config.yml", __FILE__)
|
7
|
+
@expected_merge = {
|
8
|
+
:require=>["ApplicationVndBonfireXml", "something"],
|
9
|
+
:username=>"crohr",
|
10
|
+
:gateway=>"ssh.bonfire.grid5000.fr",
|
11
|
+
:uri=>"https://api.bonfire-project.eu/",
|
12
|
+
:password=>"p4ssw0rd"
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should take a hash and store it with symbolized keys" do
|
17
|
+
config = Restfully::Configuration.new("a" => 1, :b => "hello", "c" => [1,2,3])
|
18
|
+
config.options.should == {:a=>1, :b=>"hello", :c=>[1, 2, 3]}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should correctly load a configuration file" do
|
22
|
+
config = Restfully::Configuration.load(@config_file)
|
23
|
+
config.options.should == {
|
24
|
+
:require=>["ApplicationVndBonfireXml"],
|
25
|
+
:username=>"someone",
|
26
|
+
:uri=>"https://api.bonfire-project.eu/",
|
27
|
+
:password=>"p4ssw0rd",
|
28
|
+
:gateway=>"ssh.bonfire.grid5000.fr"
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should correctly overwrite the options defined in the configuration file with other options given on initialization" do
|
33
|
+
config = Restfully::Configuration.new(:username => "crohr", :require => ['something'], :configuration_file => @config_file)
|
34
|
+
config.expand
|
35
|
+
config.options.should == @expected_merge.merge(
|
36
|
+
:configuration_file=>@config_file
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should correctly merge two configs" do
|
41
|
+
config1 = Restfully::Configuration.new(:username => "crohr", :require => ['something'])
|
42
|
+
config2 = Restfully::Configuration.load(@config_file)
|
43
|
+
config2.merge(config1).options.should == @expected_merge
|
44
|
+
end
|
45
|
+
end
|
@@ -16,7 +16,7 @@ describe Restfully::Session do
|
|
16
16
|
session = Restfully::Session.new(@config.merge("key" => "value"))
|
17
17
|
session.logger.should == @logger
|
18
18
|
session.uri.should == Addressable::URI.parse(@uri)
|
19
|
-
session.config.should == {:wait_before_retry=>5, :key=>"value", :retry_on_error=>5}
|
19
|
+
session.config.to_hash.should == {:wait_before_retry=>5, :key=>"value", :retry_on_error=>5}
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should raise an error if no URI given" do
|
@@ -53,7 +53,7 @@ describe Restfully::Session do
|
|
53
53
|
}]]]
|
54
54
|
end
|
55
55
|
|
56
|
-
it "should disable the
|
56
|
+
it "should disable the client-side cache if given :no_cache" do
|
57
57
|
session = Restfully::Session.new(@config.merge({
|
58
58
|
:cache => false
|
59
59
|
}))
|
@@ -68,6 +68,11 @@ describe Restfully::Session do
|
|
68
68
|
res.should_receive(:load).and_return(res)
|
69
69
|
session.root.should == res
|
70
70
|
end
|
71
|
+
|
72
|
+
it "should return itself when calling #session" do
|
73
|
+
session = Restfully::Session.new(@config)
|
74
|
+
session.session.should == session
|
75
|
+
end
|
71
76
|
|
72
77
|
it "should fetch the root path [URI path present]" do
|
73
78
|
session = Restfully::Session.new(
|
@@ -130,10 +135,10 @@ describe Restfully::Session do
|
|
130
135
|
instance_of(Restfully::HTTP::Request)
|
131
136
|
)
|
132
137
|
|
133
|
-
@session.transmit :get, @path, {
|
138
|
+
@session.send(:transmit, :get, @path, {
|
134
139
|
:query => {:k1 => "v1", :k2 => "v2"},
|
135
140
|
:headers => {'X-Header' => 'value'}
|
136
|
-
}
|
141
|
+
})
|
137
142
|
end
|
138
143
|
|
139
144
|
it "should make an authenticated get request" do
|
@@ -145,10 +150,10 @@ describe Restfully::Session do
|
|
145
150
|
)
|
146
151
|
@session.should_receive(:process)
|
147
152
|
@session.authenticate :username => 'crohr', :password => 'p4ssw0rd'
|
148
|
-
@session.transmit :get, @path, {
|
153
|
+
@session.send(:transmit, :get, @path, {
|
149
154
|
:query => {:k1 => "v1", :k2 => "v2"},
|
150
155
|
:headers => {'X-Header' => 'value'}
|
151
|
-
}
|
156
|
+
})
|
152
157
|
end
|
153
158
|
|
154
159
|
it "should retry for at most :max_attempts_on_connection_error if connection to the server failed" do
|
metadata
CHANGED
@@ -1,20 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restfully
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0.rc1
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Cyril Rohr
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
13
|
-
default_executable:
|
12
|
+
date: 2011-11-04 00:00:00.000000000Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: json
|
17
|
-
requirement: &
|
16
|
+
requirement: &2152514160 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ~>
|
@@ -22,10 +21,10 @@ dependencies:
|
|
22
21
|
version: '1.5'
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *2152514160
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: rest-client
|
28
|
-
requirement: &
|
27
|
+
requirement: &2152511640 !ruby/object:Gem::Requirement
|
29
28
|
none: false
|
30
29
|
requirements:
|
31
30
|
- - ~>
|
@@ -33,10 +32,10 @@ dependencies:
|
|
33
32
|
version: '1.6'
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *2152511640
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: rest-client-components
|
39
|
-
requirement: &
|
38
|
+
requirement: &2152510880 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ! '>='
|
@@ -44,10 +43,10 @@ dependencies:
|
|
44
43
|
version: '0'
|
45
44
|
type: :runtime
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
46
|
+
version_requirements: *2152510880
|
48
47
|
- !ruby/object:Gem::Dependency
|
49
48
|
name: rack-cache
|
50
|
-
requirement: &
|
49
|
+
requirement: &2152509540 !ruby/object:Gem::Requirement
|
51
50
|
none: false
|
52
51
|
requirements:
|
53
52
|
- - ! '>='
|
@@ -55,10 +54,10 @@ dependencies:
|
|
55
54
|
version: '0'
|
56
55
|
type: :runtime
|
57
56
|
prerelease: false
|
58
|
-
version_requirements: *
|
57
|
+
version_requirements: *2152509540
|
59
58
|
- !ruby/object:Gem::Dependency
|
60
59
|
name: backports
|
61
|
-
requirement: &
|
60
|
+
requirement: &2152508000 !ruby/object:Gem::Requirement
|
62
61
|
none: false
|
63
62
|
requirements:
|
64
63
|
- - ! '>='
|
@@ -66,10 +65,10 @@ dependencies:
|
|
66
65
|
version: '0'
|
67
66
|
type: :runtime
|
68
67
|
prerelease: false
|
69
|
-
version_requirements: *
|
68
|
+
version_requirements: *2152508000
|
70
69
|
- !ruby/object:Gem::Dependency
|
71
70
|
name: addressable
|
72
|
-
requirement: &
|
71
|
+
requirement: &2152506760 !ruby/object:Gem::Requirement
|
73
72
|
none: false
|
74
73
|
requirements:
|
75
74
|
- - ! '>='
|
@@ -77,10 +76,65 @@ dependencies:
|
|
77
76
|
version: '0'
|
78
77
|
type: :runtime
|
79
78
|
prerelease: false
|
80
|
-
version_requirements: *
|
79
|
+
version_requirements: *2152506760
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: ripl
|
82
|
+
requirement: &2152505220 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :runtime
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *2152505220
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: ripl-multi_line
|
93
|
+
requirement: &2152504360 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :runtime
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *2152504360
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: ripl-color_streams
|
104
|
+
requirement: &2152503480 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :runtime
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *2152503480
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: ripl-play
|
115
|
+
requirement: &2152502240 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ~>
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 0.2.1
|
121
|
+
type: :runtime
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *2152502240
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: rb-readline
|
126
|
+
requirement: &2152501420 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *2152501420
|
81
135
|
- !ruby/object:Gem::Dependency
|
82
136
|
name: rake
|
83
|
-
requirement: &
|
137
|
+
requirement: &2152500480 !ruby/object:Gem::Requirement
|
84
138
|
none: false
|
85
139
|
requirements:
|
86
140
|
- - ~>
|
@@ -88,10 +142,10 @@ dependencies:
|
|
88
142
|
version: '0.8'
|
89
143
|
type: :development
|
90
144
|
prerelease: false
|
91
|
-
version_requirements: *
|
145
|
+
version_requirements: *2152500480
|
92
146
|
- !ruby/object:Gem::Dependency
|
93
147
|
name: rspec
|
94
|
-
requirement: &
|
148
|
+
requirement: &2152499460 !ruby/object:Gem::Requirement
|
95
149
|
none: false
|
96
150
|
requirements:
|
97
151
|
- - ~>
|
@@ -99,10 +153,10 @@ dependencies:
|
|
99
153
|
version: '2'
|
100
154
|
type: :development
|
101
155
|
prerelease: false
|
102
|
-
version_requirements: *
|
156
|
+
version_requirements: *2152499460
|
103
157
|
- !ruby/object:Gem::Dependency
|
104
158
|
name: webmock
|
105
|
-
requirement: &
|
159
|
+
requirement: &2152498720 !ruby/object:Gem::Requirement
|
106
160
|
none: false
|
107
161
|
requirements:
|
108
162
|
- - ! '>='
|
@@ -110,10 +164,10 @@ dependencies:
|
|
110
164
|
version: '0'
|
111
165
|
type: :development
|
112
166
|
prerelease: false
|
113
|
-
version_requirements: *
|
167
|
+
version_requirements: *2152498720
|
114
168
|
- !ruby/object:Gem::Dependency
|
115
169
|
name: autotest
|
116
|
-
requirement: &
|
170
|
+
requirement: &2152497620 !ruby/object:Gem::Requirement
|
117
171
|
none: false
|
118
172
|
requirements:
|
119
173
|
- - ! '>='
|
@@ -121,10 +175,10 @@ dependencies:
|
|
121
175
|
version: '0'
|
122
176
|
type: :development
|
123
177
|
prerelease: false
|
124
|
-
version_requirements: *
|
178
|
+
version_requirements: *2152497620
|
125
179
|
- !ruby/object:Gem::Dependency
|
126
180
|
name: autotest-growl
|
127
|
-
requirement: &
|
181
|
+
requirement: &2152495520 !ruby/object:Gem::Requirement
|
128
182
|
none: false
|
129
183
|
requirements:
|
130
184
|
- - ! '>='
|
@@ -132,7 +186,7 @@ dependencies:
|
|
132
186
|
version: '0'
|
133
187
|
type: :development
|
134
188
|
prerelease: false
|
135
|
-
version_requirements: *
|
189
|
+
version_requirements: *2152495520
|
136
190
|
description: Consume RESTful APIs effortlessly
|
137
191
|
email:
|
138
192
|
- cyril.rohr@gmail.com
|
@@ -145,6 +199,7 @@ extra_rdoc_files:
|
|
145
199
|
files:
|
146
200
|
- bin/restfully
|
147
201
|
- lib/restfully/collection.rb
|
202
|
+
- lib/restfully/configuration.rb
|
148
203
|
- lib/restfully/error.rb
|
149
204
|
- lib/restfully/http/error.rb
|
150
205
|
- lib/restfully/http/helper.rb
|
@@ -174,10 +229,12 @@ files:
|
|
174
229
|
- spec/fixtures/bonfire-network-collection.xml
|
175
230
|
- spec/fixtures/bonfire-network-existing.xml
|
176
231
|
- spec/fixtures/bonfire-root.xml
|
232
|
+
- spec/fixtures/config.yml
|
177
233
|
- spec/fixtures/grid5000-rennes-job.json
|
178
234
|
- spec/fixtures/grid5000-rennes-jobs.json
|
179
235
|
- spec/fixtures/grid5000-rennes.json
|
180
236
|
- spec/restfully/collection_spec.rb
|
237
|
+
- spec/restfully/configuration_spec.rb
|
181
238
|
- spec/restfully/http/helper_spec.rb
|
182
239
|
- spec/restfully/http/request_spec.rb
|
183
240
|
- spec/restfully/http/response_spec.rb
|
@@ -190,7 +247,6 @@ files:
|
|
190
247
|
- Rakefile
|
191
248
|
- LICENSE
|
192
249
|
- README.md
|
193
|
-
has_rdoc: true
|
194
250
|
homepage: http://github.com/crohr/restfully
|
195
251
|
licenses: []
|
196
252
|
post_install_message:
|
@@ -212,7 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
212
268
|
version: '1.3'
|
213
269
|
requirements: []
|
214
270
|
rubyforge_project:
|
215
|
-
rubygems_version: 1.
|
271
|
+
rubygems_version: 1.8.11
|
216
272
|
signing_key:
|
217
273
|
specification_version: 3
|
218
274
|
summary: Consume RESTful APIs effortlessly
|
@@ -226,10 +282,12 @@ test_files:
|
|
226
282
|
- spec/fixtures/bonfire-network-collection.xml
|
227
283
|
- spec/fixtures/bonfire-network-existing.xml
|
228
284
|
- spec/fixtures/bonfire-root.xml
|
285
|
+
- spec/fixtures/config.yml
|
229
286
|
- spec/fixtures/grid5000-rennes-job.json
|
230
287
|
- spec/fixtures/grid5000-rennes-jobs.json
|
231
288
|
- spec/fixtures/grid5000-rennes.json
|
232
289
|
- spec/restfully/collection_spec.rb
|
290
|
+
- spec/restfully/configuration_spec.rb
|
233
291
|
- spec/restfully/http/helper_spec.rb
|
234
292
|
- spec/restfully/http/request_spec.rb
|
235
293
|
- spec/restfully/http/response_spec.rb
|