http 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of http might be problematic. Click here for more details.

data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --backtrace
data/CHANGES.md ADDED
@@ -0,0 +1,7 @@
1
+ 0.0.1
2
+ -----
3
+ * Initial half-baked release
4
+
5
+ 0.0.0
6
+ -----
7
+ * Vapoware release to claim the "http" gem name >:D
data/README.md CHANGED
@@ -1,8 +1,74 @@
1
- HTTP
1
+ Http
2
2
  ====
3
3
 
4
- This is an HTTP toolkit for doing HTTP things in Ruby. Ruby is a great
5
- language but one of its great shortcomings is its inability to speak
6
- HTTP properly.
4
+ Ruby has always been this extremely web-focused language, and yet despite the
5
+ selection of HTTP libraries out there, I always find myself falling back on
6
+ Net::HTTP, and Net::HTTP sucks.
7
7
 
8
- Maybe I can fix that! Trololol...
8
+ Ruby should be simple and elegant and beautiful. Net::HTTP is not. I've often
9
+ found myself falling back on the Perlish horrors of open-uri just because I
10
+ found Net::HTTP to be too much of a pain. This shouldn't be!
11
+
12
+ HTTP should be simple and easy! It should be so straightforward it makes
13
+ you happy with how delightful it is to use!
14
+
15
+ Making Requests
16
+ ---------------
17
+
18
+ Let's start with getting things:
19
+
20
+ Http.get "http://www.google.com"
21
+
22
+ That's it! The result is the response body.
23
+
24
+ Don't like "Http"? No worries, this works as well:
25
+
26
+ HTTP.get "http://www.google.com"
27
+
28
+ After all, There Is More Than One Way To Do It!
29
+
30
+ Making POST requests is simple too. Want to POST a form?
31
+
32
+ Http.post "http://example.com/resource", :form => {:foo => "42"}
33
+
34
+ It's easy!
35
+
36
+ Adding Headers
37
+ --------------
38
+
39
+ The Http library uses the concept of chaining to simplify requests. Let's say
40
+ you want to get the latest commit of this library from Github in JSON format.
41
+ One way we could do this is by tacking a filename on the end of the URL:
42
+
43
+ Http.get "https://github.com/tarcieri/http/commit/HEAD.json"
44
+
45
+ The Github API happens to support this approach, but really this is a bit of a
46
+ hack that makes it easy for people typing URLs into the address bars of
47
+ browsers to perform the act of content negotiation. Since we have access to
48
+ the full, raw power of HTTP, we can perform content negotiation the way HTTP
49
+ intends us to, by using the Accept header:
50
+
51
+ Http.with_headers(:accept => 'application/json').
52
+ get("https://github.com/tarcieri/http/commit/HEAD")
53
+
54
+ This requests JSON from Github. Github is smart enough to understand our
55
+ request and returns a response with Content-Type: application/json. If you
56
+ happen to have a library loaded which defines the JSON constant and implements
57
+ JSON.parse, the Http library will attempt to parse the JSON response.
58
+
59
+ A shorter alias exists for HTTP.with_headers:
60
+
61
+ Http.with(:accept => 'application/json').
62
+ get("https://github.com/tarcieri/http/commit/HEAD")
63
+
64
+ Content Negotiation
65
+ -------------------
66
+
67
+ As important a concept as content negotiation is HTTP, it sure should be easy,
68
+ right? But usually it's not, and so we end up adding ".json" onto the ends of
69
+ our URLs because the existing mechanisms make it too hard. It should be easy:
70
+
71
+ Http.accept(:json).get("https://github.com/tarcieri/http/commit/HEAD")
72
+
73
+ This adds the appropriate Accept header for retrieving a JSON response for the
74
+ given resource.
data/Rakefile CHANGED
@@ -1,2 +1,7 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new
6
+
7
+ task :default => :spec
data/http.gemspec CHANGED
@@ -14,4 +14,8 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "http"
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Http::VERSION
17
+
18
+ gem.add_development_dependency 'rake'
19
+ gem.add_development_dependency 'rspec', '>= 2.6.0'
20
+ gem.add_development_dependency 'json'
17
21
  end
@@ -0,0 +1,84 @@
1
+ module Http
2
+ module Chainable
3
+ # Request a get sans response body
4
+ def head(uri, options = {})
5
+ request :head, uri, options
6
+ end
7
+
8
+ # Get a resource
9
+ def get(uri, options = {})
10
+ request :get, uri, options
11
+ end
12
+
13
+ # Post to a resource
14
+ def post(uri, options = {})
15
+ request :post, uri, options
16
+ end
17
+
18
+ # Put to a resource
19
+ def put(uri, options = {})
20
+ request :put, uri, options
21
+ end
22
+
23
+ # Delete a resource
24
+ def delete(uri, options = {})
25
+ request :delete, uri, options
26
+ end
27
+
28
+ # Echo the request back to the client
29
+ def trace(uri, options = {})
30
+ request :trace, uri, options
31
+ end
32
+
33
+ # Return the methods supported on the given URI
34
+ def options(uri, options = {})
35
+ request :options, uri, options
36
+ end
37
+
38
+ # Convert to a transparent TCP/IP tunnel
39
+ def connect(uri, options = {})
40
+ request :connect, uri, options
41
+ end
42
+
43
+ # Apply partial modifications to a resource
44
+ def patch(uri, options = {})
45
+ request :patch, uri, options
46
+ end
47
+
48
+ # Make an HTTP request with the given verb
49
+ def request(verb, uri, options = {})
50
+ if options[:headers]
51
+ headers = default_headers.merge options[:headers]
52
+ else
53
+ headers = default_headers
54
+ end
55
+
56
+ Client.new(uri).request verb, options.merge(:headers => headers)
57
+ end
58
+
59
+ # Make a request with the given headers
60
+ def with_headers(headers)
61
+ Parameters.new default_headers.merge(headers)
62
+ end
63
+ alias_method :with, :with_headers
64
+
65
+ # Accept the given MIME type(s)
66
+ def accept(type)
67
+ if type.is_a? String
68
+ with :accept => type
69
+ else
70
+ mime_type = Http::MimeType[type]
71
+ raise ArgumentError, "unknown MIME type: #{type}" unless mime_type
72
+ with :accept => mime_type.type
73
+ end
74
+ end
75
+
76
+ def default_headers
77
+ @default_headers ||= {}
78
+ end
79
+
80
+ def default_headers=(headers)
81
+ @default_headers = headers
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,100 @@
1
+ module Http
2
+ # We all know what HTTP clients are, right?
3
+ class Client
4
+ # I swear I'll document that nebulous options hash
5
+ def initialize(uri, options = {})
6
+ if uri.is_a? URI
7
+ @uri = uri
8
+ else
9
+ # Why the FUCK can't Net::HTTP do this?
10
+ @uri = URI(uri)
11
+ end
12
+
13
+ @options = {:response => :parsed_body}.merge(options)
14
+ end
15
+
16
+ # Request a get sans response body
17
+ def head(uri, options = {})
18
+ request :head, options
19
+ end
20
+
21
+ # Get a resource
22
+ def get(uri, options = {})
23
+ request :get, options
24
+ end
25
+
26
+ # Post to a resource
27
+ def post(uri, options = {})
28
+ request :post, options
29
+ end
30
+
31
+ # Put to a resource
32
+ def put(uri, options = {})
33
+ request :put, options
34
+ end
35
+
36
+ # Delete a resource
37
+ def delete(uri, options = {})
38
+ request :delete, options
39
+ end
40
+
41
+ # Echo the request back to the client
42
+ def trace(uri, options = {})
43
+ request :trace, options
44
+ end
45
+
46
+ # Return the methods supported on the given URI
47
+ def options(uri, options = {})
48
+ request :options, options
49
+ end
50
+
51
+ # Convert to a transparent TCP/IP tunnel
52
+ def connect(uri, options = {})
53
+ request :connect, options
54
+ end
55
+
56
+ # Apply partial modifications to a resource
57
+ def patch(uri, options = {})
58
+ request :patch, options
59
+ end
60
+
61
+ # Make an HTTP request
62
+ def request(verb, options = {})
63
+ # Red, green, refactor tomorrow :/
64
+ options = @options.merge(options)
65
+ raw_headers = options[:headers] || {}
66
+
67
+ # Stringify keys :/
68
+ headers = {}
69
+ raw_headers.each { |k,v| headers[k.to_s] = v }
70
+
71
+ http = Net::HTTP.new(@uri.host, @uri.port)
72
+
73
+ # Why the FUCK can't Net::HTTP do this either?!
74
+ http.use_ssl = true if @uri.is_a? URI::HTTPS
75
+
76
+ request_class = Net::HTTP.const_get(verb.to_s.capitalize)
77
+ request = request_class.new(@uri.request_uri, headers)
78
+ request.set_form_data(options[:form]) if options[:form]
79
+
80
+ response = http.request(request)
81
+
82
+ case options[:response]
83
+ when :parsed_body
84
+ parse_response response
85
+ else
86
+ response.body
87
+ end
88
+ end
89
+
90
+ # Parse the response body according to its content type
91
+ def parse_response(response)
92
+ if response['content-type']
93
+ mime_type = MimeType[response['content-type'].split(/;\s*/).first]
94
+ return mime_type.parse(response.body) if mime_type
95
+ end
96
+
97
+ response.body
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,51 @@
1
+ module Http
2
+ # Yes, Http bundles its own MIME type library. Maybe it should be spun off
3
+ # as a separate gem or something.
4
+ class MimeType
5
+ @mime_types, @shortcuts = {}, {}
6
+
7
+ class << self
8
+ def register(obj)
9
+ @mime_types[obj.type] = obj
10
+ @shortcuts[obj.shortcut] = obj if obj.shortcut
11
+ end
12
+
13
+ def [](type)
14
+ if type.is_a? Symbol
15
+ @shortcuts[type]
16
+ else
17
+ @mime_types[type]
18
+ end
19
+ end
20
+ end
21
+
22
+ attr_reader :type, :shortcut
23
+
24
+ def initialize(type, shortcut = nil)
25
+ @type, @shortcut = type, shortcut
26
+ @parse_with = @emit_with = nil
27
+
28
+ self.class.register self
29
+ end
30
+
31
+ # Define
32
+ def parse_with(&block)
33
+ @parse_with = block
34
+ end
35
+
36
+ def emit_with(&block)
37
+ @emit_with = block
38
+ end
39
+
40
+ def parse(obj)
41
+ @parse_with ? @parse_with[obj] : obj
42
+ end
43
+
44
+ def emit(obj)
45
+ @emit_with ? @emit_with[obj] : obj
46
+ end
47
+ end
48
+ end
49
+
50
+ # MIME type registry
51
+ require 'http/mime_types/json'
@@ -0,0 +1,19 @@
1
+ json = Http::MimeType.new 'application/json', :json
2
+
3
+ json.parse_with do |obj|
4
+ if defined?(JSON) and JSON.respond_to? :parse
5
+ JSON.parse(obj)
6
+ else
7
+ obj
8
+ end
9
+ end
10
+
11
+ json.emit_with do |obj|
12
+ if obj.is_a? String
13
+ obj
14
+ elsif obj.respond_to? :to_json
15
+ obj.to_json
16
+ else
17
+ obj
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module Http
2
+ class Parameters
3
+ include Chainable
4
+
5
+ def initialize(headers = {})
6
+ self.default_headers = headers
7
+ end
8
+
9
+ def []=(field, value)
10
+ default_headers[field.downcase] = value
11
+ end
12
+
13
+ def [](field)
14
+ default_headers[field.downcase]
15
+ end
16
+ end
17
+ end
data/lib/http/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Http
2
- VERSION = "0.0.0"
2
+ VERSION = "0.0.1"
3
3
  end
data/lib/http.rb CHANGED
@@ -1,5 +1,18 @@
1
- require "http/version"
1
+ require 'http/version'
2
+ require 'http/chainable'
3
+ require 'http/client'
4
+ require 'http/mime_type'
5
+ require 'http/parameters'
2
6
 
7
+ # THIS IS ENTIRELY TEMPORARY, I ASSURE YOU
8
+ require 'net/https'
9
+ require 'uri'
10
+
11
+ # Http, it can be simple!
3
12
  module Http
4
- # Coming soon!
13
+ extend Chainable
5
14
  end
15
+
16
+ # TIMTOWTDI!
17
+ HTTP = Http
18
+ HttpClient = Http::Client
data/spec/http_spec.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+
4
+ describe Http do
5
+ context "getting resources" do
6
+ it "should be easy" do
7
+ # Fuck it, we'll do it live! (Testing against WEBRick or something coming soon)
8
+ response = Http.get "http://www.google.com"
9
+ response.should match(/<!doctype html>/)
10
+ end
11
+
12
+ context "with headers" do
13
+ it "should be easy" do
14
+ response = Http.accept(:json).get("https://github.com/tarcieri/http/commit/HEAD")
15
+
16
+ # Congratulations first committer, your prize is to break the build!
17
+ response['commit']['author']['name'].should == "Tony Arcieri"
18
+ end
19
+ end
20
+ end
21
+
22
+ context "posting to resources" do
23
+ it "should be easy" do
24
+ fragment = "<!doctype html><html><head><title>example</title></head></html>"
25
+ response = Http.post "http://validator.w3.org/check", :form => {:fragment => fragment}
26
+
27
+ response.should match(/HTML5/)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,2 @@
1
+ $:.push File.expand_path("../lib")
2
+ require 'http'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: http
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.0
5
+ version: 0.0.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Tony Arcieri
@@ -11,9 +11,41 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-10-06 00:00:00 Z
15
- dependencies: []
16
-
14
+ date: 2011-10-11 00:00:00 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rake
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 2.6.0
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: json
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id003
17
49
  description: HTTP so awesome it will lure Catherine Zeta Jones into your unicorn petting zoo
18
50
  email:
19
51
  - tony.arcieri@gmail.com
@@ -25,16 +57,25 @@ extra_rdoc_files: []
25
57
 
26
58
  files:
27
59
  - .gitignore
60
+ - .rspec
61
+ - CHANGES.md
28
62
  - Gemfile
29
63
  - LICENSE.txt
30
64
  - README.md
31
65
  - Rakefile
32
66
  - http.gemspec
33
67
  - lib/http.rb
68
+ - lib/http/chainable.rb
69
+ - lib/http/client.rb
70
+ - lib/http/mime_type.rb
71
+ - lib/http/mime_types/json.rb
72
+ - lib/http/parameters.rb
34
73
  - lib/http/version.rb
35
74
  - parser/common.rl
36
75
  - parser/http.rl
37
76
  - parser/multipart.rl
77
+ - spec/http_spec.rb
78
+ - spec/spec_helper.rb
38
79
  homepage: https://github.com/tarcieri/http
39
80
  licenses: []
40
81
 
@@ -62,5 +103,6 @@ rubygems_version: 1.8.10
62
103
  signing_key:
63
104
  specification_version: 3
64
105
  summary: Made entirely of Ruby (and Ragel and C and Java)
65
- test_files: []
66
-
106
+ test_files:
107
+ - spec/http_spec.rb
108
+ - spec/spec_helper.rb