webmachine 0.1.0 → 0.2.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/Gemfile +11 -3
- data/README.md +55 -27
- data/lib/webmachine/adapters/mongrel.rb +84 -0
- data/lib/webmachine/adapters/webrick.rb +12 -3
- data/lib/webmachine/adapters.rb +1 -7
- data/lib/webmachine/configuration.rb +30 -0
- data/lib/webmachine/decision/conneg.rb +7 -72
- data/lib/webmachine/decision/flow.rb +13 -11
- data/lib/webmachine/decision/fsm.rb +1 -9
- data/lib/webmachine/decision/helpers.rb +27 -7
- data/lib/webmachine/errors.rb +1 -0
- data/lib/webmachine/headers.rb +12 -3
- data/lib/webmachine/locale/en.yml +2 -2
- data/lib/webmachine/media_type.rb +117 -0
- data/lib/webmachine/resource/callbacks.rb +9 -0
- data/lib/webmachine/streaming.rb +3 -3
- data/lib/webmachine/version.rb +1 -1
- data/lib/webmachine.rb +3 -1
- data/pkg/webmachine-0.1.0/Gemfile +16 -0
- data/pkg/webmachine-0.1.0/Guardfile +11 -0
- data/pkg/webmachine-0.1.0/README.md +90 -0
- data/pkg/webmachine-0.1.0/Rakefile +31 -0
- data/pkg/webmachine-0.1.0/examples/webrick.rb +19 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/adapters/webrick.rb +74 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/adapters.rb +15 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision/conneg.rb +304 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision/flow.rb +502 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision/fsm.rb +79 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision/helpers.rb +80 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision.rb +12 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/dispatcher/route.rb +85 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/dispatcher.rb +40 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/errors.rb +37 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/headers.rb +16 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/locale/en.yml +28 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/request.rb +56 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/resource/callbacks.rb +362 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/resource/encodings.rb +36 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/resource.rb +48 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/response.rb +49 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/streaming.rb +27 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/translation.rb +11 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/version.rb +4 -0
- data/pkg/webmachine-0.1.0/lib/webmachine.rb +19 -0
- data/pkg/webmachine-0.1.0/spec/spec_helper.rb +13 -0
- data/pkg/webmachine-0.1.0/spec/tests.org +57 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/decision/conneg_spec.rb +152 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/decision/flow_spec.rb +1030 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/dispatcher/route_spec.rb +109 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/dispatcher_spec.rb +34 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/headers_spec.rb +19 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/request_spec.rb +24 -0
- data/pkg/webmachine-0.1.0/webmachine.gemspec +44 -0
- data/pkg/webmachine-0.1.0.gem +0 -0
- data/spec/webmachine/configuration_spec.rb +27 -0
- data/spec/webmachine/decision/conneg_spec.rb +18 -11
- data/spec/webmachine/decision/flow_spec.rb +2 -0
- data/spec/webmachine/decision/helpers_spec.rb +105 -0
- data/spec/webmachine/errors_spec.rb +13 -0
- data/spec/webmachine/headers_spec.rb +2 -1
- data/spec/webmachine/media_type_spec.rb +78 -0
- data/webmachine.gemspec +4 -1
- metadata +69 -11
@@ -52,15 +52,7 @@ module Webmachine
|
|
52
52
|
Webmachine.render_error(code, request, response)
|
53
53
|
when 304
|
54
54
|
response.headers.delete('Content-Type')
|
55
|
-
|
56
|
-
response.headers['ETag'] = ensure_quoted_header(etag)
|
57
|
-
end
|
58
|
-
if expires = resource.expires
|
59
|
-
response.headers['Expires'] = expires.httpdate
|
60
|
-
end
|
61
|
-
if modified = resource.last_modified
|
62
|
-
response.headers['Last-Modified'] = modified.httpdate
|
63
|
-
end
|
55
|
+
add_caching_headers
|
64
56
|
end
|
65
57
|
response.code = code
|
66
58
|
resource.finish_request
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'webmachine/streaming'
|
2
|
+
require 'webmachine/media_type'
|
3
|
+
|
2
4
|
module Webmachine
|
3
5
|
module Decision
|
4
6
|
# Methods that assist the Decision {Flow}.
|
@@ -28,11 +30,19 @@ module Webmachine
|
|
28
30
|
resource.send(encoder, resource.send(charsetter, body))
|
29
31
|
when Enumerable
|
30
32
|
EnumerableEncoder.new(resource, encoder, charsetter, body)
|
31
|
-
when body.respond_to?(:call)
|
32
|
-
CallableEncoder.new(resource, encoder, charsetter, body)
|
33
33
|
else
|
34
|
-
|
34
|
+
if body.respond_to?(:call)
|
35
|
+
CallableEncoder.new(resource, encoder, charsetter, body)
|
36
|
+
else
|
37
|
+
resource.send(encoder, resource.send(charsetter, body))
|
38
|
+
end
|
35
39
|
end
|
40
|
+
if String === response.body
|
41
|
+
response.headers['Content-Length'] = response.body.respond_to?(:bytesize) ? response.body.bytesize.to_s : response.body.length.to_s
|
42
|
+
else
|
43
|
+
response.headers.delete 'Content-Length'
|
44
|
+
response.headers['Transfer-Encoding'] = 'chunked'
|
45
|
+
end
|
36
46
|
end
|
37
47
|
|
38
48
|
# Ensures that a header is quoted (like ETag)
|
@@ -55,10 +65,8 @@ module Webmachine
|
|
55
65
|
|
56
66
|
# Assists in receiving request bodies
|
57
67
|
def accept_helper
|
58
|
-
content_type = request.content_type || 'application/octet-stream'
|
59
|
-
|
60
|
-
metadata['mediaparams'] = mt.params
|
61
|
-
acceptable = resource.content_types_accepted.find {|ct, _| mt.type_matches?(Conneg::MediaType.parse(ct)) }
|
68
|
+
content_type = MediaType.parse(request.content_type || 'application/octet-stream')
|
69
|
+
acceptable = resource.content_types_accepted.find {|ct, _| content_type.match?(ct) }
|
62
70
|
if acceptable
|
63
71
|
resource.send(acceptable.last)
|
64
72
|
else
|
@@ -75,6 +83,18 @@ module Webmachine
|
|
75
83
|
v.unshift "Accept" if resource.content_types_provided.size > 1
|
76
84
|
end
|
77
85
|
end
|
86
|
+
|
87
|
+
def add_caching_headers
|
88
|
+
if etag = resource.generate_etag
|
89
|
+
response.headers['ETag'] = ensure_quoted_header(etag)
|
90
|
+
end
|
91
|
+
if expires = resource.expires
|
92
|
+
response.headers['Expires'] = expires.httpdate
|
93
|
+
end
|
94
|
+
if modified = resource.last_modified
|
95
|
+
response.headers['Last-Modified'] = modified.httpdate
|
96
|
+
end
|
97
|
+
end
|
78
98
|
end
|
79
99
|
end
|
80
100
|
end
|
data/lib/webmachine/errors.rb
CHANGED
@@ -12,6 +12,7 @@ module Webmachine
|
|
12
12
|
# @param [Hash] options keys to override the defaults when rendering
|
13
13
|
# the response body
|
14
14
|
def self.render_error(code, req, res, options={})
|
15
|
+
res.code = code
|
15
16
|
unless res.body
|
16
17
|
title, message = t(["errors.#{code}.title", "errors.#{code}.message"],
|
17
18
|
{ :method => req.method,
|
data/lib/webmachine/headers.rb
CHANGED
@@ -1,16 +1,25 @@
|
|
1
1
|
module Webmachine
|
2
|
-
# Case-insensitive Hash of
|
2
|
+
# Case-insensitive Hash of Request headers
|
3
3
|
class Headers < ::Hash
|
4
4
|
def [](key)
|
5
|
-
super key
|
5
|
+
super transform_key(key)
|
6
6
|
end
|
7
7
|
|
8
8
|
def []=(key,value)
|
9
|
-
super key
|
9
|
+
super transform_key(key), value
|
10
10
|
end
|
11
11
|
|
12
|
+
def delete(key)
|
13
|
+
super transform_key(key)
|
14
|
+
end
|
15
|
+
|
12
16
|
def grep(pattern)
|
13
17
|
self.class[select { |k,_| pattern === k }]
|
14
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def transform_key(key)
|
22
|
+
key.to_s.downcase
|
23
|
+
end
|
15
24
|
end
|
16
25
|
end
|
@@ -19,10 +19,10 @@ en:
|
|
19
19
|
message: "The server does not support the %{method} method."
|
20
20
|
"503":
|
21
21
|
title: 503 Service Unavailable
|
22
|
-
message: The server is currently unable to
|
22
|
+
message: The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.
|
23
23
|
create_path_nil: "post_is_create? returned true but create_path is nil! Define the create_path method in %{class}"
|
24
24
|
do_redirect: "Response had do_redirect but no Location header."
|
25
25
|
fsm_broke: "Decision FSM returned an unexpected value %{result} from decision %{state}."
|
26
|
-
invalid_media_type: "Invalid media type
|
26
|
+
invalid_media_type: "Invalid media type: %{type}"
|
27
27
|
not_resource_class: "%{class} is not a subclass of Webmachine::Resource"
|
28
28
|
process_post_invalid: "process_post returned %{result}"
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'webmachine/translation'
|
2
|
+
|
3
|
+
module Webmachine
|
4
|
+
# Encapsulates a MIME media type, with logic for matching types.
|
5
|
+
class MediaType
|
6
|
+
extend Translation
|
7
|
+
# Matches valid media types
|
8
|
+
MEDIA_TYPE_REGEX = /^\s*([^;\s]+)\s*((?:;\s*\S+\s*)*)\s*$/
|
9
|
+
|
10
|
+
# Matches sub-type parameters
|
11
|
+
PARAMS_REGEX = /;\s*([^=]+)=([^;=\s]+)/
|
12
|
+
|
13
|
+
# Creates a new MediaType by parsing an alternate representation.
|
14
|
+
# @param [MediaType, String, Array<String,Hash>] obj the raw type
|
15
|
+
# to be parsed
|
16
|
+
# @return [MediaType] the parsed media type
|
17
|
+
# @raise [ArgumentError] when the type could not be parsed
|
18
|
+
def self.parse(obj)
|
19
|
+
case obj
|
20
|
+
when MediaType
|
21
|
+
obj
|
22
|
+
when MEDIA_TYPE_REGEX
|
23
|
+
type, raw_params = $1, $2
|
24
|
+
params = Hash[raw_params.scan(PARAMS_REGEX)]
|
25
|
+
new(type, params)
|
26
|
+
else
|
27
|
+
unless Array === obj && String === obj[0] && Hash === obj[1]
|
28
|
+
raise ArgumentError, t('invalid_media_type', :type => obj.inspect)
|
29
|
+
end
|
30
|
+
type = parse(obj[0])
|
31
|
+
type.params.merge!(obj[1])
|
32
|
+
type
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [String] the MIME media type
|
37
|
+
attr_accessor :type
|
38
|
+
|
39
|
+
# @return [Hash] any type parameters, e.g. charset
|
40
|
+
attr_accessor :params
|
41
|
+
|
42
|
+
# @param [String] type the main media type, e.g. application/json
|
43
|
+
# @param [Hash] params the media type parameters
|
44
|
+
def initialize(type, params={})
|
45
|
+
@type, @params = type, params
|
46
|
+
end
|
47
|
+
|
48
|
+
# Detects whether the {MediaType} represents an open wildcard
|
49
|
+
# type, that is, "*/*" without any {#params}.
|
50
|
+
def matches_all?
|
51
|
+
@type == "*/*" && @params.empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def ==(other)
|
55
|
+
other = self.class.parse(other)
|
56
|
+
other.type == type && other.params == params
|
57
|
+
end
|
58
|
+
|
59
|
+
# Detects whether this {MediaType} matches the other {MediaType},
|
60
|
+
# taking into account wildcards. Sub-type parameters are treated
|
61
|
+
# strictly.
|
62
|
+
# @param [MediaType, String, Array<String,Hash>] other the other type
|
63
|
+
# @return [true,false] whether it is an acceptable match
|
64
|
+
def exact_match?(other)
|
65
|
+
other = self.class.parse(other)
|
66
|
+
type_matches?(other) && other.params == params
|
67
|
+
end
|
68
|
+
|
69
|
+
# Detects whether the {MediaType} is an acceptable match for the
|
70
|
+
# other {MediaType}, taking into account wildcards and satisfying
|
71
|
+
# all requested parameters, but allowing this type to have extra
|
72
|
+
# specificity.
|
73
|
+
# @param [MediaType, String, Array<String,Hash>] other the other type
|
74
|
+
# @return [true,false] whether it is an acceptable match
|
75
|
+
def match?(other)
|
76
|
+
other = self.class.parse(other)
|
77
|
+
type_matches?(other) && params_match?(other.params)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Detects whether the passed sub-type parameters are all satisfied
|
81
|
+
# by this {MediaType}. The receiver is allowed to have other
|
82
|
+
# params than the ones specified, but all specified must be equal.
|
83
|
+
# @param [Hash] params the requested params
|
84
|
+
# @return [true,false] whether it is an acceptable match
|
85
|
+
def params_match?(other)
|
86
|
+
other.all? {|k,v| params[k] == v }
|
87
|
+
end
|
88
|
+
|
89
|
+
# Reconstitutes the type into a String
|
90
|
+
# @return [String] the type as a String
|
91
|
+
def to_s
|
92
|
+
[type, *params.map {|k,v| "#{k}=#{v}" }].join(";")
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [String] The major type, e.g. "application", "text", "image"
|
96
|
+
def major
|
97
|
+
type.split("/").first
|
98
|
+
end
|
99
|
+
|
100
|
+
# @return [String] the minor or sub-type, e.g. "json", "html", "jpeg"
|
101
|
+
def minor
|
102
|
+
type.split("/").last
|
103
|
+
end
|
104
|
+
|
105
|
+
# @param [MediaType] other the other type
|
106
|
+
# @return [true,false] whether the main media type is acceptable,
|
107
|
+
# ignoring params and taking into account wildcards
|
108
|
+
def type_matches?(other)
|
109
|
+
other = self.class.parse(other)
|
110
|
+
if ["*", "*/*", type].include?(other.type)
|
111
|
+
true
|
112
|
+
else
|
113
|
+
other.major == major && other.minor == "*"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -239,6 +239,15 @@ module Webmachine
|
|
239
239
|
[]
|
240
240
|
end
|
241
241
|
|
242
|
+
# This should receive the chosen language and do something with
|
243
|
+
# it that is resource-specific. The default is to store the
|
244
|
+
# value in the @language instance variable.
|
245
|
+
# @param [String] lang the negotiated language
|
246
|
+
# @api callback
|
247
|
+
def language_chosen(lang)
|
248
|
+
@language = lang
|
249
|
+
end
|
250
|
+
|
242
251
|
# This should return a hash of encodings mapped to encoding
|
243
252
|
# methods for Content-Encodings your resource wants to
|
244
253
|
# provide. The encoding will be applied to the response body
|
data/lib/webmachine/streaming.rb
CHANGED
@@ -9,15 +9,15 @@ module Webmachine
|
|
9
9
|
include Enumerable
|
10
10
|
|
11
11
|
def each
|
12
|
-
body.each do |block|
|
13
|
-
yield @resource.send(@encoder, resource.send(@charsetter, block))
|
12
|
+
@body.each do |block|
|
13
|
+
yield @resource.send(@encoder, @resource.send(@charsetter, block))
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
class CallableEncoder < StreamingEncoder
|
19
19
|
def call
|
20
|
-
@resource.send(@encoder, @resource.send(@charsetter, body.call))
|
20
|
+
@resource.send(@encoder, @resource.send(@charsetter, @body.call))
|
21
21
|
end
|
22
22
|
|
23
23
|
def to_proc
|
data/lib/webmachine/version.rb
CHANGED
data/lib/webmachine.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'webmachine/configuration'
|
1
2
|
require 'webmachine/headers'
|
2
3
|
require 'webmachine/request'
|
3
4
|
require 'webmachine/response'
|
@@ -14,6 +15,7 @@ require 'webmachine/version'
|
|
14
15
|
module Webmachine
|
15
16
|
# Starts Webmachine serving requests
|
16
17
|
def self.run
|
17
|
-
|
18
|
+
configure unless configuration
|
19
|
+
Adapters.const_get(configuration.adapter).run
|
18
20
|
end
|
19
21
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
gemset = ENV['RVM_GEMSET'] || 'webmachine'
|
2
|
+
gemset = "@#{gemset}" unless gemset.to_s == ''
|
3
|
+
|
4
|
+
rvms = %W[ 1.9.2 ].map {|v| "#{v}#{gemset}" }
|
5
|
+
|
6
|
+
guard 'rspec', :cli => "--color --profile", :growl => true, :rvm => rvms do
|
7
|
+
watch(%r{^lib/webmachine/locale/.+$}) { "spec" }
|
8
|
+
watch(%r{^spec/.+_spec\.rb$})
|
9
|
+
watch(%r{^lib/(.+)\.rb$}){ |m| "spec/#{m[1]}_spec.rb" }
|
10
|
+
watch('spec/spec_helper.rb') { "spec" }
|
11
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# webmachine for Ruby [](http://travis-ci.org/seancribbs/webmachine-ruby)
|
2
|
+
|
3
|
+
webmachine-ruby is a port of
|
4
|
+
[Webmachine](https://github.com/basho/webmachine), which is written in
|
5
|
+
Erlang. The goal of both projects is to expose interesting parts of
|
6
|
+
the HTTP protocol to your application in a declarative way. This
|
7
|
+
means that you are less concerned with handling requests directly and
|
8
|
+
more with describing the behavior of the resources that make up your
|
9
|
+
application. Webmachine is not a web framework _per se_, but more of a
|
10
|
+
toolkit for building HTTP-friendly applications. For example, it does
|
11
|
+
not provide a templating engine or a persistence layer; those choices
|
12
|
+
are up to you.
|
13
|
+
|
14
|
+
**NOTE**: _Webmachine is NOT compatible with Rack._ This is
|
15
|
+
intentional! Rack obscures HTTP in a way that makes it hard for
|
16
|
+
Webmachine to do its job properly, and encourages people to add
|
17
|
+
middleware that might break Webmachine's behavior. Rack is also built
|
18
|
+
on the tradition of CGI, which is nice for backwards compatibility but
|
19
|
+
also an antiquated paradigm and should be scuttled (IMHO). _Rack may
|
20
|
+
be supported in the future, but only as a shim to support other web
|
21
|
+
application servers._
|
22
|
+
|
23
|
+
## Getting Started
|
24
|
+
|
25
|
+
Webmachine is very young, but it's still easy to construct an
|
26
|
+
application for it!
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require 'webmachine'
|
30
|
+
# Require any of the files that contain your resources here
|
31
|
+
require 'my_resource'
|
32
|
+
|
33
|
+
# Point all URIs at the MyResource class
|
34
|
+
Webmachine::Dispatcher.add_route(['*'], MyResource)
|
35
|
+
|
36
|
+
# Start the server, binds to port 3000 using WEBrick
|
37
|
+
Webmachine.run
|
38
|
+
```
|
39
|
+
|
40
|
+
Your resource will look something like this:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
class MyResource < Webmachine::Resource
|
44
|
+
def to_html
|
45
|
+
"<html><body>Hello, world!</body></html>"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Run the first file and your application is up. That's all there is to
|
51
|
+
it! If you want to customize your resource more, look at the available
|
52
|
+
callbacks in lib/webmachine/resource/callbacks.rb. For example, you
|
53
|
+
might want to enable "gzip" compression on your resource, for which
|
54
|
+
you can simply add an `encodings_provided` callback method:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
class MyResource < Webmachine::Resource
|
58
|
+
def encodings_provided
|
59
|
+
{"gzip" => :encode_gzip, "identity" => :encode_identity}
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_html
|
63
|
+
"<html><body>Hello, world!</body></html>"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
There are many other HTTP features exposed to your resource through
|
69
|
+
callbacks. Give them a try!
|
70
|
+
|
71
|
+
## Features
|
72
|
+
|
73
|
+
* Handles the hard parts of content negotiation, conditional
|
74
|
+
requests, and response codes for you.
|
75
|
+
* Most callbacks can interrupt the decision flow by returning an
|
76
|
+
integer response code. You generally only want to do this when new
|
77
|
+
information comes to light, requiring a modification of the response.
|
78
|
+
* Currently supports WEBrick. Other host servers are planned.
|
79
|
+
* Streaming/chunked response bodies are permitted as Enumerables or Procs.
|
80
|
+
* Unlike the Erlang original, it does real Language negotiation.
|
81
|
+
|
82
|
+
## Problems/TODOs
|
83
|
+
|
84
|
+
* Support streamed responses as Fibers.
|
85
|
+
* Configuration, command-line tools, and general polish.
|
86
|
+
* An effort has been made to make the code feel as Ruby-ish as
|
87
|
+
possible, but there is still work to do.
|
88
|
+
* Tracing is exposed as an Array of decisions visited on the response
|
89
|
+
object. You should be able to turn this off and on, and visualize
|
90
|
+
the decisions on the sequence diagram.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/package_task'
|
3
|
+
|
4
|
+
def gemspec
|
5
|
+
$webmachine_gemspec ||= Gem::Specification.load("webmachine.gemspec")
|
6
|
+
end
|
7
|
+
|
8
|
+
Gem::PackageTask.new(gemspec) do |pkg|
|
9
|
+
pkg.need_zip = false
|
10
|
+
pkg.need_tar = false
|
11
|
+
end
|
12
|
+
|
13
|
+
task :gem => :gemspec
|
14
|
+
|
15
|
+
desc %{Validate the gemspec file.}
|
16
|
+
task :gemspec do
|
17
|
+
gemspec.validate
|
18
|
+
end
|
19
|
+
|
20
|
+
desc %{Release the gem to RubyGems.org}
|
21
|
+
task :release => :gem do
|
22
|
+
system "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rspec/core'
|
26
|
+
require 'rspec/core/rake_task'
|
27
|
+
|
28
|
+
desc "Run specs"
|
29
|
+
RSpec::Core::RakeTask.new(:spec)
|
30
|
+
|
31
|
+
task :default => :spec
|