luigi-httparty 0.4.6 → 0.5.0
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/History +19 -1
- data/Rakefile +26 -21
- data/VERSION +1 -1
- data/bin/httparty +32 -21
- data/examples/basic.rb +1 -1
- data/examples/custom_parsers.rb +67 -0
- data/httparty.gemspec +25 -8
- data/lib/httparty/core_extensions.rb +10 -4
- data/lib/httparty/exceptions.rb +5 -2
- data/lib/httparty/module_inheritable_attributes.rb +2 -2
- data/lib/httparty/parser.rb +140 -0
- data/lib/httparty/request.rb +63 -57
- data/lib/httparty/response.rb +2 -1
- data/lib/httparty/version.rb +1 -1
- data/lib/httparty.rb +85 -38
- data/luigi-httparty.gemspec +128 -0
- data/spec/httparty/parser_spec.rb +154 -0
- data/spec/httparty/request_spec.rb +102 -11
- data/spec/httparty_spec.rb +164 -38
- data/spec/spec_helper.rb +2 -2
- metadata +49 -4
- data/lib/httparty/parsers.rb +0 -31
data/History
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
== 0.5.0 2009-12-07
|
2
|
+
* bug fixes
|
3
|
+
* inheritable attributes no longer mutable by subclasses (yyyc514)
|
4
|
+
* namespace BasicObject within HTTParty to avoid class name collisions (eric)
|
5
|
+
|
6
|
+
* major enhancements
|
7
|
+
* Custom Parsers via class or proc
|
8
|
+
* Deprecation warning on HTTParty::AllowedFormats
|
9
|
+
moved to HTTParty::Parser::SupportedFormats
|
10
|
+
|
11
|
+
* minor enhancements
|
12
|
+
* Curl inspired output when using the binary in verbose mode (alexvollmer)
|
13
|
+
* raise UnsupportedURIScheme when scheme is not HTTP or HTTPS (djspinmonkey)
|
14
|
+
* Allow SSL for ports other than 443 when scheme is HTTPS (stefankroes)
|
15
|
+
* Accept PEM certificates via HTTParty#pem (chrislo)
|
16
|
+
* Support HEAD and OPTION verbs (grempe)
|
17
|
+
* Verify SSL certificates when providing a PEM file (collectiveidea/danielmorrison)
|
18
|
+
|
1
19
|
== 0.4.5 2009-09-12
|
2
20
|
* bug fixes
|
3
21
|
* Fixed class-level headers overwritten by cookie management code. Closes #19
|
@@ -138,4 +156,4 @@
|
|
138
156
|
== 0.1.0 2008-07-27
|
139
157
|
|
140
158
|
* 1 major enhancement:
|
141
|
-
* Initial release
|
159
|
+
* Initial release
|
data/Rakefile
CHANGED
@@ -11,29 +11,34 @@ begin
|
|
11
11
|
gem.homepage = "http://httparty.rubyforge.org"
|
12
12
|
gem.authors = ["John Nunemaker", "Sandro Turriate"]
|
13
13
|
gem.add_dependency 'crack', '>= 0.1.1'
|
14
|
-
gem.add_development_dependency "
|
14
|
+
gem.add_development_dependency "activesupport", "~>2.3"
|
15
|
+
gem.add_development_dependency "cucumber", "~>0.4"
|
16
|
+
gem.add_development_dependency "fakeweb", "~>1.2"
|
17
|
+
gem.add_development_dependency "mongrel", "~>1.1"
|
18
|
+
gem.add_development_dependency "rspec", "1.2.9"
|
15
19
|
gem.post_install_message = "When you HTTParty, you must party hard!"
|
16
20
|
gem.rubyforge_project = 'httparty'
|
17
21
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
22
|
end
|
19
23
|
Jeweler::RubyforgeTasks.new do |rubyforge|
|
20
|
-
|
24
|
+
rubyforge.doc_task = "rdoc"
|
21
25
|
end
|
26
|
+
Jeweler::GemcutterTasks.new
|
22
27
|
rescue LoadError
|
23
28
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
24
29
|
end
|
25
30
|
|
26
31
|
require 'spec/rake/spectask'
|
27
32
|
Spec::Rake::SpecTask.new(:spec) do |spec|
|
28
|
-
spec.libs << 'lib' << 'spec'
|
29
|
-
spec.spec_files = FileList['spec/**/*_spec.rb']
|
30
|
-
spec.spec_opts = ['--options', 'spec/spec.opts']
|
33
|
+
spec.libs << 'lib' << 'spec'
|
34
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
35
|
+
spec.spec_opts = ['--options', 'spec/spec.opts']
|
31
36
|
end
|
32
37
|
|
33
38
|
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
34
|
-
spec.libs << 'lib' << 'spec'
|
35
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
-
spec.rcov = true
|
39
|
+
spec.libs << 'lib' << 'spec'
|
40
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
41
|
+
spec.rcov = true
|
37
42
|
end
|
38
43
|
|
39
44
|
task :spec => :check_dependencies
|
@@ -41,11 +46,11 @@ task :spec => :check_dependencies
|
|
41
46
|
begin
|
42
47
|
require 'cucumber/rake/task'
|
43
48
|
Cucumber::Rake::Task.new(:features)
|
44
|
-
|
49
|
+
|
45
50
|
task :features => :check_dependencies
|
46
51
|
rescue LoadError
|
47
52
|
task :features do
|
48
|
-
|
53
|
+
abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
@@ -53,19 +58,19 @@ task :default => [:spec, :features]
|
|
53
58
|
|
54
59
|
require 'rake/rdoctask'
|
55
60
|
Rake::RDocTask.new do |rdoc|
|
56
|
-
if File.exist?('VERSION')
|
57
|
-
|
58
|
-
else
|
59
|
-
|
60
|
-
end
|
61
|
+
if File.exist?('VERSION')
|
62
|
+
version = File.read('VERSION')
|
63
|
+
else
|
64
|
+
version = ""
|
65
|
+
end
|
61
66
|
|
62
|
-
rdoc.rdoc_dir = 'rdoc'
|
63
|
-
rdoc.title = "httparty #{version}"
|
64
|
-
rdoc.rdoc_files.include('README*')
|
65
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
67
|
+
rdoc.rdoc_dir = 'rdoc'
|
68
|
+
rdoc.title = "httparty #{version}"
|
69
|
+
rdoc.rdoc_files.include('README*')
|
70
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
66
71
|
end
|
67
72
|
|
68
73
|
desc 'Upload website files to rubyforge'
|
69
74
|
task :website do
|
70
|
-
sh %{rsync -av website/ jnunemaker@rubyforge.org:/var/www/gforge-projects/httparty}
|
71
|
-
end
|
75
|
+
sh %{rsync -av website/ jnunemaker@rubyforge.org:/var/www/gforge-projects/httparty}
|
76
|
+
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/bin/httparty
CHANGED
@@ -12,27 +12,22 @@ opts = {
|
|
12
12
|
:verbose => false
|
13
13
|
}
|
14
14
|
|
15
|
-
def die(msg)
|
16
|
-
STDERR.puts(msg)
|
17
|
-
exit 1
|
18
|
-
end
|
19
|
-
|
20
15
|
OptionParser.new do |o|
|
21
16
|
o.banner = "USAGE: #{$0} [options] [url]"
|
22
|
-
|
17
|
+
|
23
18
|
o.on("-f",
|
24
19
|
"--format [FORMAT]",
|
25
20
|
"Output format to use instead of pretty-print ruby: " +
|
26
21
|
"plain, json or xml") do |f|
|
27
22
|
opts[:output_format] = f.downcase.to_sym
|
28
23
|
end
|
29
|
-
|
24
|
+
|
30
25
|
o.on("-a",
|
31
26
|
"--action [ACTION]",
|
32
|
-
"HTTP action: get (default), post, put or
|
27
|
+
"HTTP action: get (default), post, put, delete, head, or options") do |a|
|
33
28
|
opts[:action] = a.downcase.to_sym
|
34
29
|
end
|
35
|
-
|
30
|
+
|
36
31
|
o.on("-d",
|
37
32
|
"--data [BODY]",
|
38
33
|
"Data to put in request body (prefix with '@' for file)") do |d|
|
@@ -42,44 +37,60 @@ OptionParser.new do |o|
|
|
42
37
|
opts[:data] = d
|
43
38
|
end
|
44
39
|
end
|
45
|
-
|
40
|
+
|
46
41
|
o.on("-H", "--header [NAME=VALUE]", "Additional HTTP headers in NAME=VALUE form") do |h|
|
47
|
-
|
42
|
+
abort "Invalid header specification, should be Name:Value" unless h =~ /.+:.+/
|
48
43
|
name, value = h.split(':')
|
49
44
|
opts[:headers][name.strip] = value.strip
|
50
45
|
end
|
51
|
-
|
46
|
+
|
52
47
|
o.on("-v", "--verbose", "If set, print verbose output") do |v|
|
53
48
|
opts[:verbose] = true
|
54
49
|
end
|
55
|
-
|
50
|
+
|
56
51
|
o.on("-u", "--user [CREDS]", "Use basic authentication. Value should be user:password") do |u|
|
57
|
-
|
52
|
+
abort "Invalid credentials format. Must be user:password" unless u =~ /.+:.+/
|
58
53
|
user, password = u.split(':')
|
59
54
|
opts[:basic_auth] = { :username => user, :password => password }
|
60
55
|
end
|
61
|
-
|
56
|
+
|
62
57
|
o.on("-h", "--help", "Show help documentation") do |h|
|
63
58
|
puts o
|
64
59
|
exit
|
65
60
|
end
|
66
61
|
end.parse!
|
67
62
|
|
68
|
-
puts "Querying #{ARGV.first} with options: #{opts.inspect}" if opts[:verbose]
|
69
63
|
|
70
64
|
if ARGV.empty?
|
71
65
|
STDERR.puts "You need to provide a URL"
|
72
66
|
STDERR.puts "USAGE: #{$0} [options] [url]"
|
73
67
|
end
|
74
68
|
|
69
|
+
def dump_headers(response)
|
70
|
+
resp_type = Net::HTTPResponse::CODE_TO_OBJ[response.code.to_s]
|
71
|
+
puts "#{response.code} #{resp_type.to_s.sub(/^Net::HTTP/, '')}"
|
72
|
+
response.headers.each do |n,v|
|
73
|
+
puts "#{n}: #{v}"
|
74
|
+
end
|
75
|
+
puts
|
76
|
+
end
|
77
|
+
|
78
|
+
if opts[:verbose]
|
79
|
+
puts "#{opts[:action].to_s.upcase} #{ARGV.first}"
|
80
|
+
opts[:headers].each do |n,v|
|
81
|
+
puts "#{n}: #{v}"
|
82
|
+
end
|
83
|
+
puts
|
84
|
+
end
|
85
|
+
|
86
|
+
response = HTTParty.send(opts[:action], ARGV.first, opts)
|
75
87
|
if opts[:output_format].nil?
|
76
|
-
response
|
77
|
-
puts "Status: #{response.code}"
|
88
|
+
dump_headers(response) if opts[:verbose]
|
78
89
|
pp response
|
79
90
|
else
|
80
91
|
print_format = opts[:output_format]
|
81
|
-
response
|
82
|
-
|
92
|
+
dump_headers(response) if opts[:verbose]
|
93
|
+
|
83
94
|
case opts[:output_format]
|
84
95
|
when :json
|
85
96
|
begin
|
@@ -95,4 +106,4 @@ else
|
|
95
106
|
else
|
96
107
|
puts response
|
97
108
|
end
|
98
|
-
end
|
109
|
+
end
|
data/examples/basic.rb
CHANGED
@@ -2,7 +2,7 @@ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
2
2
|
require File.join(dir, 'httparty')
|
3
3
|
require 'pp'
|
4
4
|
|
5
|
-
# You can also use post, put, delete in the same fashion
|
5
|
+
# You can also use post, put, delete, head, options in the same fashion
|
6
6
|
response = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
|
7
7
|
puts response.body, response.code, response.message, response.headers.inspect
|
8
8
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class ParseAtom
|
2
|
+
include HTTParty
|
3
|
+
|
4
|
+
# Support Atom along with the default parsers: xml, json, yaml, etc.
|
5
|
+
class Parser::Atom < HTTParty::Parser
|
6
|
+
SupportedFormats.merge!({"application/atom+xml" => :atom})
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
# perform atom parsing on body
|
11
|
+
def atom
|
12
|
+
body.to_atom
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
parser Parser::Atom
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
class OnlyParseAtom
|
21
|
+
include HTTParty
|
22
|
+
|
23
|
+
# Only support Atom
|
24
|
+
class Parser::OnlyAtom < HTTParty::Parser
|
25
|
+
SupportedFormats = {"application/atom+xml" => :atom}
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
# perform atom parsing on body
|
30
|
+
def atom
|
31
|
+
body.to_atom
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
parser Parser::OnlyAtom
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
class SkipParsing
|
40
|
+
include HTTParty
|
41
|
+
|
42
|
+
# Parse the response body however you like
|
43
|
+
class Parser::Simple < HTTParty::Parser
|
44
|
+
def parse
|
45
|
+
body
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
parser Parser::Simple
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
class AdHocParsing
|
54
|
+
include HTTParty
|
55
|
+
parser(
|
56
|
+
Proc.new do |body, format|
|
57
|
+
case format
|
58
|
+
when :json
|
59
|
+
body.to_json
|
60
|
+
when :xml
|
61
|
+
body.to_xml
|
62
|
+
else
|
63
|
+
body
|
64
|
+
end
|
65
|
+
end
|
66
|
+
)
|
67
|
+
end
|
data/httparty.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{httparty}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["John Nunemaker", "Sandro Turriate"]
|
12
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-12-07}
|
13
13
|
s.default_executable = %q{httparty}
|
14
14
|
s.description = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
|
15
15
|
s.email = %q{nunemaker@gmail.com}
|
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
"cucumber.yml",
|
30
30
|
"examples/aaws.rb",
|
31
31
|
"examples/basic.rb",
|
32
|
+
"examples/custom_parsers.rb",
|
32
33
|
"examples/delicious.rb",
|
33
34
|
"examples/google.rb",
|
34
35
|
"examples/rubyurl.rb",
|
@@ -51,7 +52,7 @@ Gem::Specification.new do |s|
|
|
51
52
|
"lib/httparty/core_extensions.rb",
|
52
53
|
"lib/httparty/exceptions.rb",
|
53
54
|
"lib/httparty/module_inheritable_attributes.rb",
|
54
|
-
"lib/httparty/
|
55
|
+
"lib/httparty/parser.rb",
|
55
56
|
"lib/httparty/request.rb",
|
56
57
|
"lib/httparty/response.rb",
|
57
58
|
"lib/httparty/version.rb",
|
@@ -62,6 +63,7 @@ Gem::Specification.new do |s|
|
|
62
63
|
"spec/fixtures/twitter.xml",
|
63
64
|
"spec/fixtures/undefined_method_add_node_for_nil.xml",
|
64
65
|
"spec/httparty/cookie_hash_spec.rb",
|
66
|
+
"spec/httparty/parser_spec.rb",
|
65
67
|
"spec/httparty/request_spec.rb",
|
66
68
|
"spec/httparty/response_spec.rb",
|
67
69
|
"spec/httparty_spec.rb",
|
@@ -79,12 +81,14 @@ Gem::Specification.new do |s|
|
|
79
81
|
s.summary = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
|
80
82
|
s.test_files = [
|
81
83
|
"spec/httparty/cookie_hash_spec.rb",
|
84
|
+
"spec/httparty/parser_spec.rb",
|
82
85
|
"spec/httparty/request_spec.rb",
|
83
86
|
"spec/httparty/response_spec.rb",
|
84
87
|
"spec/httparty_spec.rb",
|
85
88
|
"spec/spec_helper.rb",
|
86
89
|
"examples/aaws.rb",
|
87
90
|
"examples/basic.rb",
|
91
|
+
"examples/custom_parsers.rb",
|
88
92
|
"examples/delicious.rb",
|
89
93
|
"examples/google.rb",
|
90
94
|
"examples/rubyurl.rb",
|
@@ -98,13 +102,26 @@ Gem::Specification.new do |s|
|
|
98
102
|
|
99
103
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
100
104
|
s.add_runtime_dependency(%q<crack>, [">= 0.1.1"])
|
101
|
-
s.add_development_dependency(%q<
|
105
|
+
s.add_development_dependency(%q<activesupport>, ["~> 2.3"])
|
106
|
+
s.add_development_dependency(%q<cucumber>, ["~> 0.4"])
|
107
|
+
s.add_development_dependency(%q<fakeweb>, ["~> 1.2"])
|
108
|
+
s.add_development_dependency(%q<mongrel>, ["~> 1.1"])
|
109
|
+
s.add_development_dependency(%q<rspec>, ["= 1.2.9"])
|
102
110
|
else
|
103
111
|
s.add_dependency(%q<crack>, [">= 0.1.1"])
|
104
|
-
s.add_dependency(%q<
|
112
|
+
s.add_dependency(%q<activesupport>, ["~> 2.3"])
|
113
|
+
s.add_dependency(%q<cucumber>, ["~> 0.4"])
|
114
|
+
s.add_dependency(%q<fakeweb>, ["~> 1.2"])
|
115
|
+
s.add_dependency(%q<mongrel>, ["~> 1.1"])
|
116
|
+
s.add_dependency(%q<rspec>, ["= 1.2.9"])
|
105
117
|
end
|
106
118
|
else
|
107
119
|
s.add_dependency(%q<crack>, [">= 0.1.1"])
|
108
|
-
s.add_dependency(%q<
|
120
|
+
s.add_dependency(%q<activesupport>, ["~> 2.3"])
|
121
|
+
s.add_dependency(%q<cucumber>, ["~> 0.4"])
|
122
|
+
s.add_dependency(%q<fakeweb>, ["~> 1.2"])
|
123
|
+
s.add_dependency(%q<mongrel>, ["~> 1.1"])
|
124
|
+
s.add_dependency(%q<rspec>, ["= 1.2.9"])
|
109
125
|
end
|
110
126
|
end
|
127
|
+
|
@@ -1,7 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module HTTParty
|
2
|
+
if defined?(::BasicObject)
|
3
|
+
BasicObject = ::BasicObject #:nodoc:
|
4
|
+
else
|
5
|
+
class BasicObject #:nodoc:
|
6
|
+
instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval/ }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
5
11
|
# 1.8.6 has mistyping of transitive in if statement
|
6
12
|
require "rexml/document"
|
7
13
|
module REXML #:nodoc:
|
data/lib/httparty/exceptions.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
module HTTParty
|
2
2
|
# Exception raised when you attempt to set a non-existant format
|
3
3
|
class UnsupportedFormat < StandardError; end
|
4
|
-
|
4
|
+
|
5
|
+
# Exception raised when using a URI scheme other than HTTP or HTTPS
|
6
|
+
class UnsupportedURIScheme < StandardError; end
|
7
|
+
|
5
8
|
# Exception that is raised when request has redirected too many times
|
6
9
|
class RedirectionTooDeep < StandardError; end
|
7
|
-
end
|
10
|
+
end
|
@@ -16,10 +16,10 @@ module HTTParty
|
|
16
16
|
|
17
17
|
def inherited(subclass)
|
18
18
|
@mattr_inheritable_attrs.each do |inheritable_attribute|
|
19
|
-
instance_var = "@#{inheritable_attribute}"
|
19
|
+
instance_var = "@#{inheritable_attribute}"
|
20
20
|
subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
25
|
-
end
|
25
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
module HTTParty
|
2
|
+
# The default parser used by HTTParty, supports xml, json, html, yaml, and
|
3
|
+
# plain text.
|
4
|
+
#
|
5
|
+
# == Custom Parsers
|
6
|
+
#
|
7
|
+
# If you'd like to do your own custom parsing, subclassing HTTParty::Parser
|
8
|
+
# will make that process much easier. There are a few different ways you can
|
9
|
+
# utilize HTTParty::Parser as a superclass.
|
10
|
+
#
|
11
|
+
# @example Intercept the parsing for all formats
|
12
|
+
# class SimpleParser < HTTParty::Parser
|
13
|
+
# def parse
|
14
|
+
# perform_parsing
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# @example Add the atom format and parsing method to the default parser
|
19
|
+
# class AtomParsingIncluded < HTTParty::Parser
|
20
|
+
# SupportedFormats.merge!(
|
21
|
+
# {"application/atom+xml" => :atom}
|
22
|
+
# )
|
23
|
+
#
|
24
|
+
# def atom
|
25
|
+
# perform_atom_parsing
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @example Only support the atom format
|
30
|
+
# class ParseOnlyAtom < HTTParty::Parser
|
31
|
+
# SupportedFormats = {"application/atom+xml" => :atom}
|
32
|
+
#
|
33
|
+
# def atom
|
34
|
+
# perform_atom_parsing
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# @abstract Read the Custom Parsers section for more information.
|
39
|
+
class Parser
|
40
|
+
SupportedFormats = {
|
41
|
+
'text/xml' => :xml,
|
42
|
+
'application/xml' => :xml,
|
43
|
+
'application/json' => :json,
|
44
|
+
'text/json' => :json,
|
45
|
+
'application/javascript' => :json,
|
46
|
+
'text/javascript' => :json,
|
47
|
+
'text/html' => :html,
|
48
|
+
'application/x-yaml' => :yaml,
|
49
|
+
'text/yaml' => :yaml,
|
50
|
+
'text/plain' => :plain
|
51
|
+
}
|
52
|
+
|
53
|
+
# The response body of the request
|
54
|
+
# @return [String]
|
55
|
+
attr_reader :body
|
56
|
+
|
57
|
+
# The intended parsing format for the request
|
58
|
+
# @return [Symbol] e.g. :json
|
59
|
+
attr_reader :format
|
60
|
+
|
61
|
+
# @param [String] body the response body
|
62
|
+
# @param [Symbol] format the response format
|
63
|
+
# @return parsed response
|
64
|
+
def self.call(body, format)
|
65
|
+
new(body, format).parse
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Hash] the SupportedFormats hash
|
69
|
+
def self.formats
|
70
|
+
const_get(:SupportedFormats)
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param [String] mimetype response MIME type
|
74
|
+
# @return [Symbol]
|
75
|
+
# @return [nil] mime type not supported
|
76
|
+
def self.format_from_mimetype(mimetype)
|
77
|
+
formats[formats.keys.detect {|k| mimetype.include?(k)}]
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Array<Symbol>] list of supported formats
|
81
|
+
def self.supported_formats
|
82
|
+
formats.values.uniq
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param [Symbol] format e.g. :json, :xml
|
86
|
+
# @return [Boolean]
|
87
|
+
def self.supports_format?(format)
|
88
|
+
supported_formats.include?(format)
|
89
|
+
end
|
90
|
+
|
91
|
+
def initialize(body, format)
|
92
|
+
@body = body
|
93
|
+
@format = format
|
94
|
+
end
|
95
|
+
private_class_method :new
|
96
|
+
|
97
|
+
# @return [Object] the parsed body
|
98
|
+
# @return [nil] when the response body is nil or an empty string
|
99
|
+
def parse
|
100
|
+
return nil if body.nil? || body.empty?
|
101
|
+
if supports_format?
|
102
|
+
parse_supported_format
|
103
|
+
else
|
104
|
+
body
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
protected
|
109
|
+
|
110
|
+
def xml
|
111
|
+
Crack::XML.parse(body)
|
112
|
+
end
|
113
|
+
|
114
|
+
def json
|
115
|
+
Crack::JSON.parse(body)
|
116
|
+
end
|
117
|
+
|
118
|
+
def yaml
|
119
|
+
YAML.load(body)
|
120
|
+
end
|
121
|
+
|
122
|
+
def html
|
123
|
+
body
|
124
|
+
end
|
125
|
+
|
126
|
+
def plain
|
127
|
+
body
|
128
|
+
end
|
129
|
+
|
130
|
+
def supports_format?
|
131
|
+
self.class.supports_format?(format)
|
132
|
+
end
|
133
|
+
|
134
|
+
def parse_supported_format
|
135
|
+
send(format)
|
136
|
+
rescue NoMethodError
|
137
|
+
raise NotImplementedError, "#{self.class.name} has not implemented a parsing method for the #{format.inspect} format."
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|