sawyer 0.0.4 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +0 -123
- data/lib/sawyer.rb +2 -1
- data/lib/sawyer/agent.rb +16 -2
- data/lib/sawyer/hal_rels_parser.rb +13 -0
- data/lib/sawyer/relation.rb +14 -4
- data/lib/sawyer/resource.rb +58 -10
- data/lib/sawyer/response.rb +1 -2
- data/lib/sawyer/serializer.rb +14 -3
- data/sawyer.gemspec +24 -69
- data/script/console +8 -0
- data/script/package +8 -0
- data/script/release +18 -0
- data/script/test +5 -0
- data/test/agent_test.rb +55 -0
- data/test/relation_test.rb +52 -0
- data/test/resource_test.rb +36 -13
- data/test/response_test.rb +10 -0
- metadata +17 -22
- data/SPEC.md +0 -71
- data/example/client.rb +0 -50
- data/example/nigiri.schema.json +0 -47
- data/example/server.rb +0 -114
- data/example/user.schema.json +0 -51
data/Rakefile
CHANGED
@@ -1,47 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
-
require 'date'
|
4
|
-
|
5
|
-
#############################################################################
|
6
|
-
#
|
7
|
-
# Helper functions
|
8
|
-
#
|
9
|
-
#############################################################################
|
10
|
-
|
11
|
-
def name
|
12
|
-
@name ||= Dir['*.gemspec'].first.split('.').first
|
13
|
-
end
|
14
|
-
|
15
|
-
def version
|
16
|
-
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
17
|
-
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
18
|
-
end
|
19
|
-
|
20
|
-
def date
|
21
|
-
Date.today.to_s
|
22
|
-
end
|
23
|
-
|
24
|
-
def rubyforge_project
|
25
|
-
name
|
26
|
-
end
|
27
|
-
|
28
|
-
def gemspec_file
|
29
|
-
"#{name}.gemspec"
|
30
|
-
end
|
31
|
-
|
32
|
-
def gem_file
|
33
|
-
"#{name}-#{version}.gem"
|
34
|
-
end
|
35
|
-
|
36
|
-
def replace_header(head, header_name)
|
37
|
-
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
38
|
-
end
|
39
|
-
|
40
|
-
#############################################################################
|
41
|
-
#
|
42
|
-
# Standard tasks
|
43
|
-
#
|
44
|
-
#############################################################################
|
45
3
|
|
46
4
|
task :default => :test
|
47
5
|
|
@@ -52,84 +10,3 @@ Rake::TestTask.new(:test) do |test|
|
|
52
10
|
test.verbose = true
|
53
11
|
end
|
54
12
|
|
55
|
-
desc "Open an irb session preloaded with this library"
|
56
|
-
task :console do
|
57
|
-
sh "irb -rubygems -r ./lib/#{name}.rb"
|
58
|
-
end
|
59
|
-
|
60
|
-
#############################################################################
|
61
|
-
#
|
62
|
-
# Custom tasks (add your own tasks here)
|
63
|
-
#
|
64
|
-
#############################################################################
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
#############################################################################
|
69
|
-
#
|
70
|
-
# Packaging tasks
|
71
|
-
#
|
72
|
-
#############################################################################
|
73
|
-
|
74
|
-
desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
|
75
|
-
task :release => :build do
|
76
|
-
unless `git branch` =~ /^\* master$/
|
77
|
-
puts "You must be on the master branch to release!"
|
78
|
-
exit!
|
79
|
-
end
|
80
|
-
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
81
|
-
sh "git tag v#{version}"
|
82
|
-
sh "git push origin master"
|
83
|
-
sh "git push origin v#{version}"
|
84
|
-
sh "gem push pkg/#{name}-#{version}.gem"
|
85
|
-
end
|
86
|
-
|
87
|
-
desc "Build #{gem_file} into the pkg directory"
|
88
|
-
task :build => :gemspec do
|
89
|
-
sh "mkdir -p pkg"
|
90
|
-
sh "gem build #{gemspec_file}"
|
91
|
-
sh "mv #{gem_file} pkg"
|
92
|
-
end
|
93
|
-
|
94
|
-
desc "Generate #{gemspec_file}"
|
95
|
-
task :gemspec => :validate do
|
96
|
-
# read spec file and split out manifest section
|
97
|
-
spec = File.read(gemspec_file)
|
98
|
-
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
99
|
-
|
100
|
-
# replace name version and date
|
101
|
-
replace_header(head, :name)
|
102
|
-
replace_header(head, :version)
|
103
|
-
replace_header(head, :date)
|
104
|
-
#comment this out if your rubyforge_project has a different name
|
105
|
-
replace_header(head, :rubyforge_project)
|
106
|
-
|
107
|
-
# determine file list from git ls-files
|
108
|
-
files = `git ls-files`.
|
109
|
-
split("\n").
|
110
|
-
sort.
|
111
|
-
reject { |file| file =~ /^\./ }.
|
112
|
-
reject { |file| file =~ /^(rdoc|pkg)/ }.
|
113
|
-
map { |file| " #{file}" }.
|
114
|
-
join("\n")
|
115
|
-
|
116
|
-
# piece file back together and write
|
117
|
-
manifest = " s.files = %w[\n#{files}\n ]\n"
|
118
|
-
spec = [head, manifest, tail].join(" # = MANIFEST =\n")
|
119
|
-
File.open(gemspec_file, 'w') { |io| io.write(spec) }
|
120
|
-
puts "Updated #{gemspec_file}"
|
121
|
-
end
|
122
|
-
|
123
|
-
desc "Validate #{gemspec_file}"
|
124
|
-
task :validate do
|
125
|
-
libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
|
126
|
-
unless libfiles.empty?
|
127
|
-
puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
|
128
|
-
exit!
|
129
|
-
end
|
130
|
-
unless Dir['VERSION*'].empty?
|
131
|
-
puts "A `VERSION` file at root level violates Gem best practices."
|
132
|
-
exit!
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
data/lib/sawyer.rb
CHANGED
data/lib/sawyer/agent.rb
CHANGED
@@ -5,6 +5,9 @@ module Sawyer
|
|
5
5
|
class Agent
|
6
6
|
NO_BODY = Set.new([:get, :head])
|
7
7
|
|
8
|
+
attr_accessor :links_parser
|
9
|
+
attr_accessor :allow_undefined_methods
|
10
|
+
|
8
11
|
class << self
|
9
12
|
attr_writer :serializer
|
10
13
|
end
|
@@ -33,8 +36,11 @@ module Sawyer
|
|
33
36
|
# Yields the Faraday::Connection if a block is given.
|
34
37
|
def initialize(endpoint, options = nil)
|
35
38
|
@endpoint = endpoint
|
36
|
-
@conn = (options && options[:faraday]) || Faraday.new
|
39
|
+
@conn = (options && options[:faraday]) || Faraday.new
|
37
40
|
@serializer = (options && options[:serializer]) || self.class.serializer
|
41
|
+
@links_parser = (options && options[:links_parser]) || HalLinksParser.new
|
42
|
+
@allow_undefined_methods = (options && options[:allow_undefined_methods])
|
43
|
+
@conn.url_prefix = @endpoint
|
38
44
|
yield @conn if block_given?
|
39
45
|
end
|
40
46
|
|
@@ -42,7 +48,7 @@ module Sawyer
|
|
42
48
|
#
|
43
49
|
# Returns a Sawyer::Relation::Map.
|
44
50
|
def rels
|
45
|
-
@rels ||= root.data.
|
51
|
+
@rels ||= root.data._rels
|
46
52
|
end
|
47
53
|
|
48
54
|
# Public: Retains a reference to the root response of the API.
|
@@ -115,12 +121,20 @@ module Sawyer
|
|
115
121
|
@serializer.decode(str)
|
116
122
|
end
|
117
123
|
|
124
|
+
def parse_links(data)
|
125
|
+
@links_parser.parse(data)
|
126
|
+
end
|
127
|
+
|
118
128
|
def expand_url(url, options = nil)
|
119
129
|
tpl = url.respond_to?(:expand) ? url : URITemplate.new(url.to_s)
|
120
130
|
expand = tpl.method(:expand)
|
121
131
|
options ? expand.call(options) : expand.call
|
122
132
|
end
|
123
133
|
|
134
|
+
def allow_undefined_methods?
|
135
|
+
!!@allow_undefined_methods
|
136
|
+
end
|
137
|
+
|
124
138
|
def inspect
|
125
139
|
%(<#{self.class} #{@endpoint}>)
|
126
140
|
end
|
data/lib/sawyer/relation.rb
CHANGED
@@ -13,7 +13,7 @@ module Sawyer
|
|
13
13
|
#
|
14
14
|
# Returns nothing.
|
15
15
|
def <<(rel)
|
16
|
-
@map[rel.name] = rel
|
16
|
+
@map[rel.name] = rel if rel
|
17
17
|
end
|
18
18
|
|
19
19
|
# Gets the raw Relation by its name.
|
@@ -82,7 +82,12 @@ module Sawyer
|
|
82
82
|
#
|
83
83
|
# Returns a Relation.
|
84
84
|
def self.from_link(agent, name, options)
|
85
|
-
|
85
|
+
case options
|
86
|
+
when Hash
|
87
|
+
new agent, name, options[:href], options[:method]
|
88
|
+
when String
|
89
|
+
new agent, name, options
|
90
|
+
end
|
86
91
|
end
|
87
92
|
|
88
93
|
# A Relation represents an available next action for a resource.
|
@@ -94,7 +99,11 @@ module Sawyer
|
|
94
99
|
def initialize(agent, name, href, method = nil)
|
95
100
|
@agent = agent
|
96
101
|
@name = name.to_sym
|
97
|
-
@
|
102
|
+
@href = href
|
103
|
+
begin
|
104
|
+
@href_template = URITemplate.new(href.to_s)
|
105
|
+
rescue URITemplate::RFC6570::Invalid => e
|
106
|
+
end
|
98
107
|
|
99
108
|
methods = nil
|
100
109
|
|
@@ -225,6 +234,7 @@ module Sawyer
|
|
225
234
|
end
|
226
235
|
|
227
236
|
def href(options = nil)
|
237
|
+
return @href if @href_template.nil?
|
228
238
|
method = @href_template.method(:expand)
|
229
239
|
options ? method.call(options) : method.call
|
230
240
|
end
|
@@ -243,7 +253,7 @@ module Sawyer
|
|
243
253
|
# Returns a Sawyer::Response.
|
244
254
|
def call(data = nil, options = nil)
|
245
255
|
m = options && options[:method]
|
246
|
-
if m && !@available_methods.include?(m == :head ? :get : m)
|
256
|
+
if m && !@agent.allow_undefined_methods? && !@available_methods.include?(m == :head ? :get : m)
|
247
257
|
raise ArgumentError, "method #{m.inspect} is not available: #{@available_methods.to_a.inspect}"
|
248
258
|
end
|
249
259
|
|
data/lib/sawyer/resource.rb
CHANGED
@@ -1,20 +1,26 @@
|
|
1
1
|
module Sawyer
|
2
2
|
class Resource
|
3
|
-
SPECIAL_METHODS = Set.new
|
3
|
+
SPECIAL_METHODS = Set.new(%w(agent rels fields))
|
4
4
|
attr_reader :_agent, :_rels, :_fields
|
5
|
+
attr_reader :attrs
|
6
|
+
alias to_hash attrs
|
5
7
|
|
6
8
|
# Initializes a Resource with the given data.
|
7
9
|
#
|
8
10
|
# agent - The Sawyer::Agent that made the API request.
|
9
11
|
# data - Hash of key/value properties.
|
10
|
-
def initialize(agent, data)
|
12
|
+
def initialize(agent, data = {})
|
11
13
|
@_agent = agent
|
12
|
-
|
13
|
-
@
|
14
|
+
data, links = agent.parse_links(data)
|
15
|
+
@_rels = Relation.from_links(agent, links)
|
16
|
+
@_fields = Set.new
|
17
|
+
@_metaclass = (class << self; self; end)
|
18
|
+
@attrs = {}
|
14
19
|
data.each do |key, value|
|
15
20
|
@_fields << key
|
16
|
-
|
21
|
+
@attrs[key.to_sym] = process_value(value)
|
17
22
|
end
|
23
|
+
@_metaclass.send(:attr_accessor, *data.keys)
|
18
24
|
end
|
19
25
|
|
20
26
|
# Processes an individual value of this resource. Hashes get exploded
|
@@ -40,6 +46,29 @@ module Sawyer
|
|
40
46
|
@_fields.include? key
|
41
47
|
end
|
42
48
|
|
49
|
+
# Allow fields to be retrieved via Hash notation
|
50
|
+
#
|
51
|
+
# method - key name
|
52
|
+
#
|
53
|
+
# Returns the value from attrs if exists
|
54
|
+
def [](method)
|
55
|
+
send(method.to_sym)
|
56
|
+
rescue NoMethodError
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# Allow fields to be set via Hash notation
|
61
|
+
#
|
62
|
+
# method - key name
|
63
|
+
# value - value to set for the attr key
|
64
|
+
#
|
65
|
+
# Returns - value
|
66
|
+
def []=(method, value)
|
67
|
+
send("#{method}=", value)
|
68
|
+
rescue NoMethodError
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
43
72
|
ATTR_SETTER = '='.freeze
|
44
73
|
ATTR_PREDICATE = '?'.freeze
|
45
74
|
|
@@ -47,14 +76,14 @@ module Sawyer
|
|
47
76
|
def method_missing(method, *args)
|
48
77
|
attr_name, suffix = method.to_s.scan(/([a-z0-9\_]+)(\?|\=)?$/i).first
|
49
78
|
if suffix == ATTR_SETTER
|
50
|
-
|
79
|
+
@_metaclass.send(:attr_accessor, attr_name)
|
51
80
|
@_fields << attr_name.to_sym
|
52
|
-
|
53
|
-
elsif @_fields.include?(attr_name.to_sym)
|
54
|
-
value =
|
81
|
+
send(method, args.first)
|
82
|
+
elsif attr_name && @_fields.include?(attr_name.to_sym)
|
83
|
+
value = @attrs[attr_name.to_sym]
|
55
84
|
case suffix
|
56
85
|
when nil
|
57
|
-
|
86
|
+
@_metaclass.send(:attr_accessor, attr_name)
|
58
87
|
value
|
59
88
|
when ATTR_PREDICATE then !!value
|
60
89
|
end
|
@@ -64,6 +93,25 @@ module Sawyer
|
|
64
93
|
super
|
65
94
|
end
|
66
95
|
end
|
96
|
+
|
97
|
+
# Wire up accessor methods to pull from attrs
|
98
|
+
def self.attr_accessor(*attrs)
|
99
|
+
attrs.each do |attribute|
|
100
|
+
class_eval do
|
101
|
+
define_method attribute do
|
102
|
+
@attrs[attribute.to_sym]
|
103
|
+
end
|
104
|
+
|
105
|
+
define_method "#{attribute}=" do |value|
|
106
|
+
@attrs[attribute.to_sym] = value
|
107
|
+
end
|
108
|
+
|
109
|
+
define_method "#{attribute}?" do
|
110
|
+
!!@attrs[attribute.to_sym]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
67
115
|
end
|
68
116
|
end
|
69
117
|
|
data/lib/sawyer/response.rb
CHANGED
data/lib/sawyer/serializer.rb
CHANGED
@@ -49,6 +49,8 @@ module Sawyer
|
|
49
49
|
@dump.call(encode_object(data))
|
50
50
|
end
|
51
51
|
|
52
|
+
alias dump encode
|
53
|
+
|
52
54
|
# Public: Decodes a String into an Object (usually a Hash or Array of
|
53
55
|
# Hashes).
|
54
56
|
#
|
@@ -60,10 +62,12 @@ module Sawyer
|
|
60
62
|
decode_object(@load.call(data))
|
61
63
|
end
|
62
64
|
|
65
|
+
alias load decode
|
66
|
+
|
63
67
|
def encode_object(data)
|
64
68
|
case data
|
65
69
|
when Hash then encode_hash(data)
|
66
|
-
when Array then data.map { |o| encode_object(
|
70
|
+
when Array then data.map { |o| encode_object(o) }
|
67
71
|
else data
|
68
72
|
end
|
69
73
|
end
|
@@ -73,6 +77,7 @@ module Sawyer
|
|
73
77
|
case value = hash[key]
|
74
78
|
when Date then hash[key] = value.to_time.utc.xmlschema
|
75
79
|
when Time then hash[key] = value.utc.xmlschema
|
80
|
+
when Hash then hash[key] = encode_hash(value)
|
76
81
|
end
|
77
82
|
end
|
78
83
|
hash
|
@@ -81,7 +86,7 @@ module Sawyer
|
|
81
86
|
def decode_object(data)
|
82
87
|
case data
|
83
88
|
when Hash then decode_hash(data)
|
84
|
-
when Array then data.map { |o| decode_object(
|
89
|
+
when Array then data.map { |o| decode_object(o) }
|
85
90
|
else data
|
86
91
|
end
|
87
92
|
end
|
@@ -94,13 +99,19 @@ module Sawyer
|
|
94
99
|
end
|
95
100
|
|
96
101
|
def decode_hash_value(key, value)
|
97
|
-
if key
|
102
|
+
if time_field?(key, value)
|
98
103
|
Time.parse(value)
|
99
104
|
elsif value.is_a?(Hash)
|
100
105
|
decode_hash(value)
|
106
|
+
elsif value.is_a?(Array)
|
107
|
+
value.map { |o| decode_hash_value(key, o) }
|
101
108
|
else
|
102
109
|
value
|
103
110
|
end
|
104
111
|
end
|
112
|
+
|
113
|
+
def time_field?(key, value)
|
114
|
+
value && key =~ /_(at|on)$/
|
115
|
+
end
|
105
116
|
end
|
106
117
|
end
|
data/sawyer.gemspec
CHANGED
@@ -1,78 +1,33 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
## You can find comprehensive Gem::Specification documentation, at
|
6
|
-
## http://docs.rubygems.org/read/chapter/20
|
7
|
-
Gem::Specification.new do |s|
|
8
|
-
s.specification_version = 2 if s.respond_to? :specification_version=
|
9
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
10
|
-
s.rubygems_version = '1.3.5'
|
1
|
+
lib = "sawyer"
|
2
|
+
lib_file = File.expand_path("../lib/#{lib}.rb", __FILE__)
|
3
|
+
File.read(lib_file) =~ /\bVERSION\s*=\s*["'](.+?)["']/
|
4
|
+
version = $1
|
11
5
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
s.name = 'sawyer'
|
16
|
-
s.version = '0.0.4'
|
17
|
-
s.date = '2012-09-27'
|
18
|
-
s.rubyforge_project = 'sawyer'
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.specification_version = 2 if spec.respond_to? :specification_version=
|
8
|
+
spec.required_rubygems_version = Gem::Requirement.new(">= 1.3.5") if spec.respond_to? :required_rubygems_version=
|
19
9
|
|
20
|
-
|
21
|
-
|
22
|
-
s.summary = "Secret User Agent of HTTP"
|
23
|
-
s.description = "#{s.summary} built on Faraday"
|
10
|
+
spec.name = lib
|
11
|
+
spec.version = version
|
24
12
|
|
25
|
-
|
26
|
-
## better to set the email to an email list or something. If you don't have
|
27
|
-
## a custom homepage, consider using your GitHub URL or the like.
|
28
|
-
s.authors = ["Rick Olson"]
|
29
|
-
s.email = 'technoweenie@gmail.com'
|
30
|
-
s.homepage = 'https://github.com/technoweenie/sawyer'
|
13
|
+
spec.summary = "Secret User Agent of HTTP"
|
31
14
|
|
32
|
-
|
33
|
-
|
34
|
-
|
15
|
+
spec.authors = ["Rick Olson"]
|
16
|
+
spec.email = 'technoweenie@gmail.com'
|
17
|
+
spec.homepage = 'https://github.com/lostisland/sawyer'
|
18
|
+
spec.licenses = ['MIT']
|
35
19
|
|
36
|
-
|
37
|
-
|
38
|
-
s.add_dependency('faraday', ['~> 0.8.4'])
|
39
|
-
s.add_dependency('uri_template', ['~> 0.5.0'])
|
20
|
+
spec.add_dependency 'faraday', ['~> 0.8.4']
|
21
|
+
spec.add_dependency 'uri_template', ['~> 0.5.0']
|
40
22
|
|
41
|
-
|
42
|
-
|
43
|
-
|
23
|
+
spec.files = %w(Gemfile LICENSE.md README.md Rakefile)
|
24
|
+
spec.files << "#{lib}.gemspec"
|
25
|
+
spec.files += Dir.glob("lib/**/*.rb")
|
26
|
+
spec.files += Dir.glob("test/**/*.rb")
|
27
|
+
spec.files += Dir.glob("script/*")
|
44
28
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
# = MANIFEST =
|
49
|
-
s.files = %w[
|
50
|
-
Gemfile
|
51
|
-
LICENSE.md
|
52
|
-
README.md
|
53
|
-
Rakefile
|
54
|
-
SPEC.md
|
55
|
-
example/client.rb
|
56
|
-
example/nigiri.schema.json
|
57
|
-
example/server.rb
|
58
|
-
example/user.schema.json
|
59
|
-
lib/sawyer.rb
|
60
|
-
lib/sawyer/agent.rb
|
61
|
-
lib/sawyer/relation.rb
|
62
|
-
lib/sawyer/resource.rb
|
63
|
-
lib/sawyer/response.rb
|
64
|
-
lib/sawyer/serializer.rb
|
65
|
-
sawyer.gemspec
|
66
|
-
test/agent_test.rb
|
67
|
-
test/helper.rb
|
68
|
-
test/relation_test.rb
|
69
|
-
test/resource_test.rb
|
70
|
-
test/response_test.rb
|
71
|
-
]
|
72
|
-
# = MANIFEST =
|
73
|
-
|
74
|
-
## Test files will be grabbed from the file list. Make sure the path glob
|
75
|
-
## matches what you actually use.
|
76
|
-
s.test_files = s.files.select { |path| path =~ /^test\/.*_test\.rb/ }
|
29
|
+
dev_null = File.exist?('/dev/null') ? '/dev/null' : 'NUL'
|
30
|
+
git_files = `git ls-files -z 2>#{dev_null}`
|
31
|
+
spec.files &= git_files.split("\0") if $?.success?
|
77
32
|
end
|
78
33
|
|
data/script/console
ADDED
data/script/package
ADDED
data/script/release
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
# Usage: script/release
|
3
|
+
# Build the package, tag a commit, push it to origin, and then release the
|
4
|
+
# package publicly.
|
5
|
+
|
6
|
+
set -e
|
7
|
+
|
8
|
+
version="$(script/package | grep Version: | awk '{print $2}')"
|
9
|
+
[ -n "$version" ] || exit 1
|
10
|
+
|
11
|
+
git commit --allow-empty -a -m "Release $version"
|
12
|
+
git tag "v$version"
|
13
|
+
git push origin
|
14
|
+
git push origin "v$version"
|
15
|
+
git push legacy
|
16
|
+
git push legacy "v$version"
|
17
|
+
gem push pkg/*-${version}.gem
|
18
|
+
|
data/script/test
ADDED
data/test/agent_test.rb
CHANGED
@@ -2,6 +2,16 @@ require File.expand_path("../helper", __FILE__)
|
|
2
2
|
|
3
3
|
module Sawyer
|
4
4
|
class AgentTest < TestCase
|
5
|
+
|
6
|
+
class InlineRelsParser
|
7
|
+
def parse(data)
|
8
|
+
links = {}
|
9
|
+
data.keys.select {|k| k[/_url$/] }.each {|k| links[k.to_s.gsub(/_url$/, '')] = data.delete(k) }
|
10
|
+
|
11
|
+
return data, links
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
5
15
|
def setup
|
6
16
|
@stubs = Faraday::Adapter::Test::Stubs.new
|
7
17
|
@agent = Sawyer::Agent.new "http://foo.com/a/" do |conn|
|
@@ -25,6 +35,31 @@ module Sawyer
|
|
25
35
|
assert_equal :get, @agent.rels[:users].method
|
26
36
|
end
|
27
37
|
|
38
|
+
def test_allows_custom_rel_parsing
|
39
|
+
@stubs.get '/a/' do |env|
|
40
|
+
assert_equal 'foo.com', env[:url].host
|
41
|
+
|
42
|
+
[200, {}, Sawyer::Agent.encode(
|
43
|
+
:url => '/',
|
44
|
+
:users_url => '/users',
|
45
|
+
:repos_url => '/repos')]
|
46
|
+
end
|
47
|
+
|
48
|
+
agent = Sawyer::Agent.new "http://foo.com/a/" do |conn|
|
49
|
+
conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
|
50
|
+
conn.adapter :test, @stubs
|
51
|
+
end
|
52
|
+
agent.links_parser = InlineRelsParser.new
|
53
|
+
|
54
|
+
assert_equal 200, agent.root.status
|
55
|
+
|
56
|
+
assert_equal '/users', agent.rels[:users].href
|
57
|
+
assert_equal :get, agent.rels[:users].method
|
58
|
+
assert_equal '/repos', agent.rels[:repos].href
|
59
|
+
assert_equal :get, agent.rels[:repos].method
|
60
|
+
|
61
|
+
end
|
62
|
+
|
28
63
|
def test_saves_root_endpoint
|
29
64
|
@stubs.get '/a/' do |env|
|
30
65
|
[200, {}, '{}']
|
@@ -79,6 +114,26 @@ module Sawyer
|
|
79
114
|
:query => {:foo => 'bar'}
|
80
115
|
assert_equal 200, res.status
|
81
116
|
end
|
117
|
+
|
118
|
+
def test_encodes_and_decodes_times
|
119
|
+
time = Time.at(Time.now.to_i)
|
120
|
+
data = {:a => 1, :b => true, :c => 'c', :created_at => time, :published_at => nil}
|
121
|
+
data = [data.merge(:foo => [data])]
|
122
|
+
encoded = Sawyer::Agent.encode(data)
|
123
|
+
decoded = Sawyer::Agent.decode(encoded)
|
124
|
+
|
125
|
+
2.times do
|
126
|
+
assert_equal 1, decoded.size
|
127
|
+
decoded = decoded.shift
|
128
|
+
|
129
|
+
assert_equal 1, decoded[:a]
|
130
|
+
assert_equal true, decoded[:b]
|
131
|
+
assert_equal 'c', decoded[:c]
|
132
|
+
assert_equal time, decoded[:created_at]
|
133
|
+
assert_nil decoded[:published_at]
|
134
|
+
decoded = decoded[:foo]
|
135
|
+
end
|
136
|
+
end
|
82
137
|
end
|
83
138
|
end
|
84
139
|
|
data/test/relation_test.rb
CHANGED
@@ -28,6 +28,23 @@ module Sawyer
|
|
28
28
|
assert_kind_of URITemplate, rel.href_template
|
29
29
|
end
|
30
30
|
|
31
|
+
def test_builds_rels_from_hash
|
32
|
+
index = {
|
33
|
+
'self' => '/users/1'
|
34
|
+
}
|
35
|
+
|
36
|
+
rels = Sawyer::Relation.from_links(nil, index)
|
37
|
+
|
38
|
+
assert_equal 1, rels.size
|
39
|
+
assert_equal [:self], rels.keys
|
40
|
+
assert rel = rels[:self]
|
41
|
+
assert_equal :self, rel.name
|
42
|
+
assert_equal '/users/1', rel.href
|
43
|
+
assert_equal :get, rel.method
|
44
|
+
assert_equal [:get], rel.available_methods.to_a
|
45
|
+
assert_kind_of URITemplate, rel.href_template
|
46
|
+
end
|
47
|
+
|
31
48
|
def test_builds_rels_from_hash_index
|
32
49
|
index = {
|
33
50
|
'self' => {:href => '/users/1'}
|
@@ -109,6 +126,41 @@ module Sawyer
|
|
109
126
|
assert_equal 404, rel.get.status
|
110
127
|
assert_equal 200, rel.get(:uri => {'user' => 'octocat', 'repo' => 'hello', 'a' => 1, 'b' => 2}).status
|
111
128
|
end
|
129
|
+
|
130
|
+
def test_handles_invalid_uri
|
131
|
+
hash = {:href => '/this has spaces', :method => 'post'}
|
132
|
+
rel = Sawyer::Relation.from_link(nil, :self, hash)
|
133
|
+
|
134
|
+
assert_equal :self, rel.name
|
135
|
+
assert_equal '/this has spaces', rel.href
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_allows_all_methods_when_not_in_strict_mode
|
139
|
+
|
140
|
+
agent = Sawyer::Agent.new "http://foo.com/a/", :allow_undefined_methods => true do |conn|
|
141
|
+
conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
|
142
|
+
conn.adapter :test do |stubs|
|
143
|
+
stubs.get '/a/1' do
|
144
|
+
[200, {}, '{}']
|
145
|
+
end
|
146
|
+
stubs.delete '/a/1' do
|
147
|
+
[204, {}, '{}']
|
148
|
+
end
|
149
|
+
stubs.post '/a/1' do
|
150
|
+
[200, {}, '{}']
|
151
|
+
end
|
152
|
+
stubs.put '/a/1' do
|
153
|
+
[204, {}, '{}']
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
rel = Sawyer::Relation.new agent, :self, "/a/1"
|
159
|
+
assert_equal 200, rel.get.status
|
160
|
+
assert_equal 200, rel.post.status
|
161
|
+
assert_equal 204, rel.put.status
|
162
|
+
assert_equal 204, rel.delete.status
|
163
|
+
end
|
112
164
|
end
|
113
165
|
end
|
114
166
|
|
data/test/resource_test.rb
CHANGED
@@ -2,19 +2,28 @@ require File.expand_path("../helper", __FILE__)
|
|
2
2
|
|
3
3
|
module Sawyer
|
4
4
|
class ResourceTest < TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@stubs = Faraday::Adapter::Test::Stubs.new
|
8
|
+
@agent = Sawyer::Agent.new "http://foo.com/a/" do |conn|
|
9
|
+
conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
|
10
|
+
conn.adapter :test, @stubs
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
5
14
|
def test_accessible_keys
|
6
|
-
res = Resource.new
|
15
|
+
res = Resource.new @agent, :a => 1,
|
7
16
|
:_links => {:self => {:href => '/'}}
|
8
17
|
|
9
18
|
assert_equal 1, res.a
|
10
19
|
assert res.rels[:self]
|
11
|
-
assert_equal
|
20
|
+
assert_equal @agent, res.agent
|
12
21
|
assert_equal 1, res.fields.size
|
13
22
|
assert res.fields.include?(:a)
|
14
23
|
end
|
15
24
|
|
16
25
|
def test_clashing_keys
|
17
|
-
res = Resource.new
|
26
|
+
res = Resource.new @agent, :agent => 1, :rels => 2, :fields => 3,
|
18
27
|
:_links => {:self => {:href => '/'}}
|
19
28
|
|
20
29
|
assert_equal 1, res.agent
|
@@ -22,7 +31,7 @@ module Sawyer
|
|
22
31
|
assert_equal 3, res.fields
|
23
32
|
|
24
33
|
assert res._rels[:self]
|
25
|
-
assert_equal
|
34
|
+
assert_equal @agent, res._agent
|
26
35
|
assert_equal 3, res._fields.size
|
27
36
|
[:agent, :rels, :fields].each do |f|
|
28
37
|
assert res._fields.include?(f)
|
@@ -30,7 +39,7 @@ module Sawyer
|
|
30
39
|
end
|
31
40
|
|
32
41
|
def test_nested_object
|
33
|
-
res = Resource.new
|
42
|
+
res = Resource.new @agent,
|
34
43
|
:user => {:id => 1, :_links => {:self => {:href => '/users/1'}}},
|
35
44
|
:_links => {:self => {:href => '/'}}
|
36
45
|
|
@@ -41,7 +50,7 @@ module Sawyer
|
|
41
50
|
end
|
42
51
|
|
43
52
|
def test_nested_collection
|
44
|
-
res = Resource.new
|
53
|
+
res = Resource.new @agent,
|
45
54
|
:users => [{:id => 1, :_links => {:self => {:href => '/users/1'}}}],
|
46
55
|
:_links => {:self => {:href => '/'}}
|
47
56
|
|
@@ -55,7 +64,7 @@ module Sawyer
|
|
55
64
|
end
|
56
65
|
|
57
66
|
def test_attribute_predicates
|
58
|
-
res = Resource.new
|
67
|
+
res = Resource.new @agent, :a => 1, :b => true, :c => nil, :d => false
|
59
68
|
|
60
69
|
assert res.a?
|
61
70
|
assert res.b?
|
@@ -64,7 +73,7 @@ module Sawyer
|
|
64
73
|
end
|
65
74
|
|
66
75
|
def test_attribute_setter
|
67
|
-
res = Resource.new
|
76
|
+
res = Resource.new @agent, :a => 1
|
68
77
|
assert_equal 1, res.a
|
69
78
|
assert !res.key?(:b)
|
70
79
|
|
@@ -74,10 +83,10 @@ module Sawyer
|
|
74
83
|
end
|
75
84
|
|
76
85
|
def test_dynamic_attribute_methods_from_getter
|
77
|
-
res = Resource.new
|
78
|
-
assert
|
79
|
-
assert
|
80
|
-
assert
|
86
|
+
res = Resource.new @agent, :a => 1
|
87
|
+
assert res.key?(:a)
|
88
|
+
assert res.respond_to?(:a)
|
89
|
+
assert res.respond_to?(:a=)
|
81
90
|
|
82
91
|
assert_equal 1, res.a
|
83
92
|
assert res.respond_to?(:a)
|
@@ -85,7 +94,7 @@ module Sawyer
|
|
85
94
|
end
|
86
95
|
|
87
96
|
def test_dynamic_attribute_methods_from_setter
|
88
|
-
res = Resource.new
|
97
|
+
res = Resource.new @agent, :a => 1
|
89
98
|
assert !res.key?(:b)
|
90
99
|
assert !res.respond_to?(:b)
|
91
100
|
assert !res.respond_to?(:b=)
|
@@ -95,5 +104,19 @@ module Sawyer
|
|
95
104
|
assert res.respond_to?(:b)
|
96
105
|
assert res.respond_to?(:b=)
|
97
106
|
end
|
107
|
+
|
108
|
+
def test_attrs
|
109
|
+
res = Resource.new @agent, :a => 1
|
110
|
+
hash = {:a => 1 }
|
111
|
+
assert_equal hash, res.attrs
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_handle_hash_notation_with_string_key
|
115
|
+
res = Resource.new @agent, :a => 1
|
116
|
+
assert_equal 1, res['a']
|
117
|
+
|
118
|
+
res[:b] = 2
|
119
|
+
assert_equal 2, res.b
|
120
|
+
end
|
98
121
|
end
|
99
122
|
end
|
data/test/response_test.rb
CHANGED
@@ -16,6 +16,11 @@ module Sawyer
|
|
16
16
|
}
|
17
17
|
)]
|
18
18
|
end
|
19
|
+
|
20
|
+
stub.get '/emails' do
|
21
|
+
emails = %w(rick@example.com technoweenie@example.com)
|
22
|
+
[200, {'Content-Type' => 'application/json'}, Sawyer::Agent.encode(emails)]
|
23
|
+
end
|
19
24
|
end
|
20
25
|
end
|
21
26
|
|
@@ -55,6 +60,11 @@ module Sawyer
|
|
55
60
|
assert_equal 201, res.status
|
56
61
|
assert_nil res.data
|
57
62
|
end
|
63
|
+
|
64
|
+
def test_handles_arrays_of_strings
|
65
|
+
res = @agent.call(:get, '/emails')
|
66
|
+
assert_equal 'rick@example.com', res.data.first
|
67
|
+
end
|
58
68
|
end
|
59
69
|
end
|
60
70
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sawyer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: 0.5.0
|
46
|
-
description:
|
46
|
+
description:
|
47
47
|
email: technoweenie@gmail.com
|
48
48
|
executables: []
|
49
49
|
extensions: []
|
@@ -53,25 +53,26 @@ files:
|
|
53
53
|
- LICENSE.md
|
54
54
|
- README.md
|
55
55
|
- Rakefile
|
56
|
-
-
|
57
|
-
- example/client.rb
|
58
|
-
- example/nigiri.schema.json
|
59
|
-
- example/server.rb
|
60
|
-
- example/user.schema.json
|
61
|
-
- lib/sawyer.rb
|
56
|
+
- sawyer.gemspec
|
62
57
|
- lib/sawyer/agent.rb
|
58
|
+
- lib/sawyer/hal_rels_parser.rb
|
63
59
|
- lib/sawyer/relation.rb
|
64
60
|
- lib/sawyer/resource.rb
|
65
61
|
- lib/sawyer/response.rb
|
66
62
|
- lib/sawyer/serializer.rb
|
67
|
-
- sawyer.
|
63
|
+
- lib/sawyer.rb
|
68
64
|
- test/agent_test.rb
|
69
65
|
- test/helper.rb
|
70
66
|
- test/relation_test.rb
|
71
67
|
- test/resource_test.rb
|
72
68
|
- test/response_test.rb
|
73
|
-
|
74
|
-
|
69
|
+
- script/console
|
70
|
+
- script/package
|
71
|
+
- script/release
|
72
|
+
- script/test
|
73
|
+
homepage: https://github.com/lostisland/sawyer
|
74
|
+
licenses:
|
75
|
+
- MIT
|
75
76
|
post_install_message:
|
76
77
|
rdoc_options: []
|
77
78
|
require_paths:
|
@@ -82,23 +83,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
83
|
- - ! '>='
|
83
84
|
- !ruby/object:Gem::Version
|
84
85
|
version: '0'
|
85
|
-
segments:
|
86
|
-
- 0
|
87
|
-
hash: -3466190819871303014
|
88
86
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
87
|
none: false
|
90
88
|
requirements:
|
91
89
|
- - ! '>='
|
92
90
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
91
|
+
version: 1.3.5
|
94
92
|
requirements: []
|
95
|
-
rubyforge_project:
|
93
|
+
rubyforge_project:
|
96
94
|
rubygems_version: 1.8.23
|
97
95
|
signing_key:
|
98
96
|
specification_version: 2
|
99
97
|
summary: Secret User Agent of HTTP
|
100
|
-
test_files:
|
101
|
-
|
102
|
-
- test/relation_test.rb
|
103
|
-
- test/resource_test.rb
|
104
|
-
- test/response_test.rb
|
98
|
+
test_files: []
|
99
|
+
has_rdoc:
|
data/SPEC.md
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
# Sawyer
|
2
|
-
|
3
|
-
To use Sawyer, create a new Agent with a URL endpoint.
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
endpoint = "http://my-api.com"
|
7
|
-
agent = Sawyer::Agent.new endpoint do |conn|
|
8
|
-
conn.headers['content-type'] = 'application/vnd.my-api+json'
|
9
|
-
end
|
10
|
-
```
|
11
|
-
|
12
|
-
From here, we can access the root to get the initial actions.
|
13
|
-
|
14
|
-
```ruby
|
15
|
-
root = agent.start
|
16
|
-
```
|
17
|
-
|
18
|
-
Every request in Sawyer returns a Sawyer::Response. It's very similar
|
19
|
-
to a raw Faraday::Response, with a few extra methods.
|
20
|
-
|
21
|
-
```ruby
|
22
|
-
# HTTP Headers
|
23
|
-
root.headers
|
24
|
-
|
25
|
-
# HTTP status
|
26
|
-
root.status
|
27
|
-
|
28
|
-
# The JSON Schema
|
29
|
-
root.schema
|
30
|
-
|
31
|
-
# The link relations
|
32
|
-
root.rels
|
33
|
-
|
34
|
-
# The contents (probably empty from the root)
|
35
|
-
root.data
|
36
|
-
```
|
37
|
-
|
38
|
-
Now, we can access a relation off the root resource.
|
39
|
-
|
40
|
-
```ruby
|
41
|
-
resource = root.data
|
42
|
-
res = resource.rels[:users].call :query => {:sort => 'login'}
|
43
|
-
|
44
|
-
# An array of users
|
45
|
-
users = res.data
|
46
|
-
```
|
47
|
-
|
48
|
-
This call returns two types of relations: relations on the collection of
|
49
|
-
users, and relations on each user. You can access the collection
|
50
|
-
resources from the response.
|
51
|
-
|
52
|
-
```ruby
|
53
|
-
# get the next page of users
|
54
|
-
res2 = res.rels[:next].call
|
55
|
-
|
56
|
-
# page 2 of the users collection
|
57
|
-
res2.data
|
58
|
-
```
|
59
|
-
|
60
|
-
Each user has it's own relations too:
|
61
|
-
|
62
|
-
```ruby
|
63
|
-
# favorite the previous user
|
64
|
-
users.each_with_index do |user, index|
|
65
|
-
res = user.rels[:favorite].call users[index-1]
|
66
|
-
if !res.success?
|
67
|
-
puts "#{user.name} could not favorite #{users[index-1].name}"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
```
|
71
|
-
|
data/example/client.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require File.expand_path("../../lib/sawyer", __FILE__)
|
2
|
-
require 'faraday'
|
3
|
-
require 'pp'
|
4
|
-
|
5
|
-
endpoint = "http://localhost:9393/"
|
6
|
-
agent = Sawyer::Agent.new(endpoint) do |http|
|
7
|
-
http.headers['content-type'] = 'application/json'
|
8
|
-
end
|
9
|
-
puts agent.inspect
|
10
|
-
puts
|
11
|
-
|
12
|
-
root = agent.start
|
13
|
-
puts root.inspect
|
14
|
-
|
15
|
-
puts "LISTING USERS"
|
16
|
-
users_rel = root.data.rels[:users]
|
17
|
-
|
18
|
-
puts users_rel.inspect
|
19
|
-
puts
|
20
|
-
|
21
|
-
users_res = users_rel.get
|
22
|
-
puts users_res.inspect
|
23
|
-
|
24
|
-
users = users_res.data
|
25
|
-
|
26
|
-
users.each do |user|
|
27
|
-
puts "#{user.login} favorites:"
|
28
|
-
|
29
|
-
fav_res = user.rels[:favorites].get
|
30
|
-
|
31
|
-
fav_res.data.each do |sushi|
|
32
|
-
puts "- #{sushi.inspect})"
|
33
|
-
end
|
34
|
-
puts
|
35
|
-
end
|
36
|
-
|
37
|
-
puts "CREATING USER"
|
38
|
-
create_user_rel = root.data.rels[:users]
|
39
|
-
|
40
|
-
puts create_user_rel.inspect
|
41
|
-
|
42
|
-
created = create_user_rel.post(:login => 'booya')
|
43
|
-
puts created.inspect
|
44
|
-
puts
|
45
|
-
|
46
|
-
puts "ADD A FAVORITE"
|
47
|
-
created_user = created.data
|
48
|
-
create_fav_res = created_user.rels[:favorites].post nil, :query => {:id => 1}
|
49
|
-
puts create_fav_res.inspect
|
50
|
-
|
data/example/nigiri.schema.json
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"type": "object",
|
3
|
-
"relations": [
|
4
|
-
{"rel": "all", "href": "/nigiri"}
|
5
|
-
],
|
6
|
-
"properties": {
|
7
|
-
"id": {
|
8
|
-
"type": "integer",
|
9
|
-
"minimum": 1,
|
10
|
-
"readonly": true
|
11
|
-
},
|
12
|
-
"name": {
|
13
|
-
"type": "string"
|
14
|
-
},
|
15
|
-
"fish": {
|
16
|
-
"type": "string"
|
17
|
-
},
|
18
|
-
"_links": {
|
19
|
-
"type": "array",
|
20
|
-
"items": {
|
21
|
-
"type": "object",
|
22
|
-
"properties": {
|
23
|
-
"rel": {
|
24
|
-
"type": "string"
|
25
|
-
},
|
26
|
-
"href": {
|
27
|
-
"type": "string",
|
28
|
-
"optional": true
|
29
|
-
},
|
30
|
-
"method": {
|
31
|
-
"type": "string",
|
32
|
-
"default": "get"
|
33
|
-
},
|
34
|
-
"schema": {
|
35
|
-
"type": "string",
|
36
|
-
"optional": true
|
37
|
-
}
|
38
|
-
},
|
39
|
-
"additionalProperties": false
|
40
|
-
},
|
41
|
-
"additionalProperties": false,
|
42
|
-
"readonly": true
|
43
|
-
}
|
44
|
-
}
|
45
|
-
}
|
46
|
-
|
47
|
-
|
data/example/server.rb
DELETED
@@ -1,114 +0,0 @@
|
|
1
|
-
require 'sinatra'
|
2
|
-
require 'yajl'
|
3
|
-
|
4
|
-
get '/' do
|
5
|
-
app_type
|
6
|
-
|
7
|
-
Yajl.dump({
|
8
|
-
:_links => {
|
9
|
-
:users => {:href => "/users", :method => 'get,post'},
|
10
|
-
:nigiri => {:href => "/nigiri"}
|
11
|
-
}
|
12
|
-
}, :pretty => true)
|
13
|
-
end
|
14
|
-
|
15
|
-
def app_type
|
16
|
-
content_type "application/vnd.sushihub+json"
|
17
|
-
end
|
18
|
-
|
19
|
-
users = [
|
20
|
-
{:id => 1, :login => 'sawyer', :created_at => Time.utc(2004, 9, 22),
|
21
|
-
:_links => {
|
22
|
-
:self => {:href => '/users/sawyer'},
|
23
|
-
:favorites => {:href => '/users/sawyer/favorites', :method => 'get,post'}
|
24
|
-
}},
|
25
|
-
{:id => 2, :login => 'faraday', :created_at => Time.utc(2004, 12, 22),
|
26
|
-
:_links => {
|
27
|
-
:self => {:href => '/users/faraday'},
|
28
|
-
:favorites => {:href => '/users/faraday/favorites', :method => 'get,post'}
|
29
|
-
}}
|
30
|
-
]
|
31
|
-
|
32
|
-
nigiri = [
|
33
|
-
{:id => 1, :name => 'sake', :fish => 'salmon',
|
34
|
-
:_links => {
|
35
|
-
:self => {:href => '/nigiri/sake'}
|
36
|
-
}},
|
37
|
-
{:id => 2, :name => 'unagi', :fish => 'eel',
|
38
|
-
:_links => {
|
39
|
-
:self => {:href => '/nigiri/unagi'}
|
40
|
-
}}
|
41
|
-
]
|
42
|
-
|
43
|
-
get '/users' do
|
44
|
-
app_type
|
45
|
-
|
46
|
-
Yajl.dump users, :pretty => true
|
47
|
-
end
|
48
|
-
|
49
|
-
new_users = {}
|
50
|
-
post '/users' do
|
51
|
-
if env['CONTENT_TYPE'].to_s !~ /json/i
|
52
|
-
halt 400, "Needs JSON"
|
53
|
-
end
|
54
|
-
|
55
|
-
app_type
|
56
|
-
|
57
|
-
hash = Yajl.load request.body.read, :symbolize_keys => true
|
58
|
-
new_users[hash[:login]] = hash
|
59
|
-
|
60
|
-
headers "Location" => "/users/#{hash[:login]}"
|
61
|
-
status 201
|
62
|
-
Yajl.dump hash.update(
|
63
|
-
:id => 3,
|
64
|
-
:created_at => Time.now.utc.xmlschema,
|
65
|
-
:_links => {
|
66
|
-
:self => {:href => "/users/#{hash[:login]}"},
|
67
|
-
:favorites => {:href => "/users/#{hash[:login]}/favorites", :method => 'get,post'}
|
68
|
-
}
|
69
|
-
), :pretty => true
|
70
|
-
end
|
71
|
-
|
72
|
-
get '/users/:login' do
|
73
|
-
headers 'Content-Type' => app_type
|
74
|
-
if hash = users.detect { |u| u[:login] == params[:login] }
|
75
|
-
Yajl.dump hash, :pretty => true
|
76
|
-
else
|
77
|
-
halt 404
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
get '/users/:login/favorites' do
|
82
|
-
app_type
|
83
|
-
|
84
|
-
case params[:login]
|
85
|
-
when users[0][:login] then Yajl.dump([nigiri[0]], :pretty => true)
|
86
|
-
when users[1][:login] then Yajl.dump([], :pretty => true)
|
87
|
-
else halt 404
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
post '/users/:login/favorites' do
|
92
|
-
if params[:id].to_i > 0
|
93
|
-
halt 201
|
94
|
-
else
|
95
|
-
halt 422
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
get '/nigiri' do
|
100
|
-
app_type
|
101
|
-
|
102
|
-
Yajl.dump nigiri, :pretty => true
|
103
|
-
end
|
104
|
-
|
105
|
-
get '/nigiri/:name' do
|
106
|
-
app_type
|
107
|
-
|
108
|
-
if hash = nigiri.detect { |n| n[:name] == params[:name] }
|
109
|
-
Yajl.dump hash, :pretty => true
|
110
|
-
else
|
111
|
-
halt(404)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
data/example/user.schema.json
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"type": "object",
|
3
|
-
"relations": [
|
4
|
-
{"rel": "all", "href": "/users"},
|
5
|
-
{"rel": "create", "href": "/users", "method": "post"},
|
6
|
-
{"rel": "favorites", "schema": "/schema/nigiri"},
|
7
|
-
{"rel": "favorites/create", "method": "post"}
|
8
|
-
],
|
9
|
-
"properties": {
|
10
|
-
"id": {
|
11
|
-
"type": "integer",
|
12
|
-
"minimum": 1,
|
13
|
-
"readonly": true
|
14
|
-
},
|
15
|
-
"login": {
|
16
|
-
"type": "string"
|
17
|
-
},
|
18
|
-
"created_at": {
|
19
|
-
"type": "string",
|
20
|
-
"pattern": "\\d{8}T\\d{6}Z",
|
21
|
-
"readonly": true
|
22
|
-
},
|
23
|
-
"_links": {
|
24
|
-
"type": "array",
|
25
|
-
"items": {
|
26
|
-
"type": "object",
|
27
|
-
"properties": {
|
28
|
-
"rel": {
|
29
|
-
"type": "string"
|
30
|
-
},
|
31
|
-
"href": {
|
32
|
-
"type": "string",
|
33
|
-
"optional": true
|
34
|
-
},
|
35
|
-
"method": {
|
36
|
-
"type": "string",
|
37
|
-
"default": "get"
|
38
|
-
},
|
39
|
-
"schema": {
|
40
|
-
"type": "string",
|
41
|
-
"optional": true
|
42
|
-
}
|
43
|
-
},
|
44
|
-
"additionalProperties": false
|
45
|
-
},
|
46
|
-
"additionalProperties": false,
|
47
|
-
"readonly": true
|
48
|
-
}
|
49
|
-
}
|
50
|
-
}
|
51
|
-
|