restfully 0.8.8 → 1.0.0.rc1
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/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
|