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 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 "rspec", "1.2.8"
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
- rubyforge.doc_task = "rdoc"
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
- abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
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
- version = File.read('VERSION')
58
- else
59
- version = ""
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.4.6
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 delete") do |a|
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
- die "Invalid header specification, should be Name:Value" unless h =~ /.+:.+/
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
- die "Invalid credentials format. Must be user:password" unless u =~ /.+:.+/
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 = HTTParty.send(opts[:action], ARGV.first, opts)
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 = HTTParty.send(opts[:action], ARGV.first, opts)
82
- puts "Status: #{response.code}"
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 `rake gemspec`
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.4.6"
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-10-29}
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/parsers.rb",
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<rspec>, ["= 1.2.8"])
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<rspec>, ["= 1.2.8"])
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<rspec>, ["= 1.2.8"])
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
- class BasicObject #:nodoc:
2
- instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval/ }
3
- end unless defined?(BasicObject)
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:
@@ -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