webmachine 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -29,12 +29,17 @@ application for it!
29
29
  require 'webmachine'
30
30
  # Require any of the files that contain your resources here
31
31
  require 'my_resource'
32
-
33
- # Point all URIs at the MyResource class
34
- Webmachine::Dispatcher.add_route(['*'], MyResource)
35
-
32
+
33
+ # Create an application which encompasses routes and configruation
34
+ MyApp = Webmachine::Application.new do |app|
35
+ app.routes do
36
+ # Point all URIs at the MyResource class
37
+ add ['*'], MyResource
38
+ end
39
+ end
40
+
36
41
  # Start the server, binds to port 8080 using WEBrick
37
- Webmachine.run
42
+ MyApp.run
38
43
  ```
39
44
 
40
45
  Your resource will look something like this:
@@ -68,29 +73,31 @@ end
68
73
  There are many other HTTP features exposed to your resource through
69
74
  {Webmachine::Resource::Callbacks}. Give them a try!
70
75
 
71
- ### Configurator
76
+ ### Application/Configurator
72
77
 
73
78
  There's a configurator that allows you to set the ip address and port
74
79
  bindings as well as a different webserver adapter. You can also add
75
- your routes in a block. Both of these call return the `Webmachine`
76
- module, so you could chain them if you like.
80
+ your routes in a block (as shown above). Both of these call return the
81
+ `Webmachine::Application` instance, so you could chain them if you
82
+ like. If you don't want to create your own separate application
83
+ object, `Webmachine.application` will return a global one.
77
84
 
78
85
  ```ruby
79
86
  require 'webmachine'
80
87
  require 'my_resource'
81
88
 
82
- Webmachine.routes do
89
+ Webmachine.application.routes do
83
90
  add ['*'], MyResource
84
91
  end
85
92
 
86
- Webmachine.configure do |config|
93
+ Webmachine.application.configure do |config|
87
94
  config.ip = '127.0.0.1'
88
95
  config.port = 3000
89
96
  config.adapter = :Mongrel
90
97
  end
91
98
 
92
99
  # Start the server.
93
- Webmachine.run
100
+ Webmachine.application.run
94
101
  ```
95
102
 
96
103
  ## Features
@@ -115,6 +122,46 @@ Webmachine.run
115
122
 
116
123
  ## Changelog
117
124
 
125
+ ### 0.4.1 February 8, 2012
126
+
127
+ 0.4.1 is a bugfix release that corrects a few minor issues. Added Sam
128
+ Goldman as a contributor. Thank you for your contributions!
129
+
130
+ * Updated README with `Webmachine::Application` examples.
131
+ * The CGI env vars `CONTENT_LENGTH` and `CONTENT_TYPE` are now being
132
+ correctly converted into their Webmachine equivalents.
133
+ * The request body given via the Rack and Mongrel adapters now
134
+ responds to `#to_s` and `#each` so it can be treated like a `String`
135
+ or `Enumerable` that yields chunks.
136
+
137
+ ### 0.4.0 February 5, 2012
138
+
139
+ 0.4.0 includes some important refactorings, isolating the idea of
140
+ global state into an Application object with its own Dispatcher and
141
+ configuration, and making Adapters into real classes with a consistent
142
+ interface. It also adds some query methods on the Request object for
143
+ the HTTP method and scheme and Route guards (matching predicates).
144
+ Added Michael Maltese, Emmanuel Gomez, and Bernerd Schaefer as
145
+ committers. Thank you for your contributions!
146
+
147
+ * Fixed `Request#query` to handle nil values for the URI query accessor.
148
+ * `Webmachine::Dispatcher` is a real class rather than a module with
149
+ state.
150
+ * `Webmachine::Application` is a class that includes its own
151
+ dispatcher and configuration. The default instance is accessible via
152
+ `Webmachine.application`.
153
+ * `Webmachine::Adapter` is now the superclass of all implemented
154
+ adapters so that they have a uniform interface.
155
+ * The Mongrel spec is skipped on JRuby since version 1.2 (pre-release)
156
+ doesn't work. Direct Mongrel support may be removed in a later
157
+ release.
158
+ * `Webmachine::Dispatcher::Route` now accepts guards, which may be
159
+ expressed as lambdas/procs or any object responding to `call`
160
+ preceding the `Resource` class in the route definition, or as a
161
+ trailing block. All guards will be passed the `Request` object when
162
+ matching the route and should return a truthy or falsey value
163
+ (without side-effects).
164
+
118
165
  ### 0.3.0 November 9, 2011
119
166
 
120
167
  0.3.0 introduces some new features, refactorings, and now has 100%
data/b/autospec ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'autospec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rspec-core', 'autospec')
data/b/gpgen ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'gpgen' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('gem_plugin', 'gpgen')
data/b/guard ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'guard' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('guard', 'guard')
data/b/htmldiff ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'htmldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('diff-lcs', 'htmldiff')
data/b/ldiff ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'ldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('diff-lcs', 'ldiff')
data/b/mongrel_rails ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'mongrel_rails' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('mongrel', 'mongrel_rails')
data/b/rackup ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rackup' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rack', 'rackup')
data/b/rake ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
data/b/rake2thor ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake2thor' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('thor', 'rake2thor')
data/b/redcarpet ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'redcarpet' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('redcarpet', 'redcarpet')
data/b/rspec ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rspec-core', 'rspec')
data/b/thor ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'thor' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('thor', 'thor')
data/b/yard ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'yard' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('yard', 'yard')
data/b/yardoc ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'yardoc' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('yard', 'yardoc')
data/b/yri ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'yri' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('yard', 'yri')
@@ -31,7 +31,7 @@ module Webmachine
31
31
  class Handler < ::Mongrel::HttpHandler
32
32
  def initialize(dispatcher)
33
33
  @dispatcher = dispatcher
34
- super
34
+ super()
35
35
  end
36
36
 
37
37
  # Processes an individual request from Mongrel through Webmachine.
@@ -41,7 +41,7 @@ module Webmachine
41
41
  request = Webmachine::Request.new(wreq.params["REQUEST_METHOD"],
42
42
  URI.parse(wreq.params["REQUEST_URI"]),
43
43
  header,
44
- wreq.body || StringIO.new(''))
44
+ RequestBody.new(wreq))
45
45
 
46
46
  response = Webmachine::Response.new
47
47
  @dispatcher.dispatch(request, response)
@@ -81,6 +81,31 @@ module Webmachine
81
81
  end
82
82
  end # class Handler
83
83
 
84
+ # Wraps a Mongrel request body so that it can behave like a
85
+ # String.
86
+ # @api private
87
+ class RequestBody
88
+ # @return the request from Mongrel
89
+ attr_reader :request
90
+
91
+ # @param request the request from Mongrel
92
+ def initialize(request)
93
+ @request = request
94
+ end
95
+
96
+ # @return [String] the request body as a string
97
+ def to_s
98
+ request.body.rewind
99
+ request.body.read
100
+ end
101
+
102
+ # @yield [chunk]
103
+ # @yieldparam [String] chunk a chunk of the request body
104
+ def each(&block)
105
+ request.body.each(&block)
106
+ end
107
+ end # class RequestBody
108
+
84
109
  end # module Mongrel
85
110
  end # module Adapters
86
111
  end # module Webmachine
@@ -51,7 +51,7 @@ module Webmachine
51
51
  request = Webmachine::Request.new(rack_req.request_method,
52
52
  URI.parse(rack_req.url),
53
53
  headers,
54
- rack_req.body)
54
+ RequestBody.new(rack_req))
55
55
 
56
56
  response = Webmachine::Response.new
57
57
  @dispatcher.dispatch(request, response)
@@ -63,6 +63,42 @@ module Webmachine
63
63
 
64
64
  [response.code.to_i, response.headers, body || []]
65
65
  end
66
+
67
+ # Wraps the Rack input so it can be treated like a String or
68
+ # Enumerable.
69
+ # @api private
70
+ class RequestBody
71
+ # @param [Rack::Request] request the Rack request
72
+ def initialize(request)
73
+ @request = request
74
+ end
75
+
76
+ # Converts the body to a String so you can work with the entire
77
+ # thing.
78
+ # @return [String] the request body as a string
79
+ def to_s
80
+ if @value
81
+ @value.join
82
+ else
83
+ @request.body.rewind
84
+ @request.body.read
85
+ end
86
+ end
87
+
88
+ # Iterates over the body in chunks. If the body has previously
89
+ # been read, this method can be called again and get the same
90
+ # sequence of chunks.
91
+ # @yield [chunk]
92
+ # @yieldparam [String] chunk a chunk of the request body
93
+ def each
94
+ if @value
95
+ @value.each {|chunk| yield chunk }
96
+ else
97
+ @value = []
98
+ @request.body.each {|chunk| @value << chunk; yield chunk }
99
+ end
100
+ end
101
+ end # class RequestBody
66
102
  end # class Rack
67
103
 
68
104
  end # module Adapters