right_develop 2.1.5 → 2.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.
Files changed (28) hide show
  1. data/VERSION +1 -1
  2. data/bin/right_develop +4 -0
  3. data/lib/right_develop.rb +1 -0
  4. data/lib/right_develop/commands.rb +2 -1
  5. data/lib/right_develop/commands/server.rb +194 -0
  6. data/lib/right_develop/testing.rb +31 -0
  7. data/lib/right_develop/testing/clients.rb +36 -0
  8. data/lib/right_develop/testing/clients/rest.rb +34 -0
  9. data/lib/right_develop/testing/clients/rest/requests.rb +38 -0
  10. data/lib/right_develop/testing/clients/rest/requests/base.rb +305 -0
  11. data/lib/right_develop/testing/clients/rest/requests/playback.rb +293 -0
  12. data/lib/right_develop/testing/clients/rest/requests/record.rb +175 -0
  13. data/lib/right_develop/testing/recording.rb +33 -0
  14. data/lib/right_develop/testing/recording/config.rb +571 -0
  15. data/lib/right_develop/testing/recording/metadata.rb +805 -0
  16. data/lib/right_develop/testing/servers/might_api/.gitignore +3 -0
  17. data/lib/right_develop/testing/servers/might_api/Gemfile +6 -0
  18. data/lib/right_develop/testing/servers/might_api/Gemfile.lock +18 -0
  19. data/lib/right_develop/testing/servers/might_api/app/base.rb +323 -0
  20. data/lib/right_develop/testing/servers/might_api/app/echo.rb +73 -0
  21. data/lib/right_develop/testing/servers/might_api/app/playback.rb +46 -0
  22. data/lib/right_develop/testing/servers/might_api/app/record.rb +45 -0
  23. data/lib/right_develop/testing/servers/might_api/config.ru +8 -0
  24. data/lib/right_develop/testing/servers/might_api/config/init.rb +47 -0
  25. data/lib/right_develop/testing/servers/might_api/lib/config.rb +204 -0
  26. data/lib/right_develop/testing/servers/might_api/lib/logger.rb +68 -0
  27. data/right_develop.gemspec +30 -2
  28. metadata +84 -34
@@ -0,0 +1,45 @@
1
+ #
2
+ # Copyright (c) 2014 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require ::File.expand_path('../base', __FILE__)
24
+
25
+ module RightDevelop::Testing::Server::MightApi::App
26
+ class Record < ::RightDevelop::Testing::Server::MightApi::App::Base
27
+
28
+ STATE_FILE_NAME = 'record_state.yml'
29
+
30
+ def initialize
31
+ super(STATE_FILE_NAME)
32
+ end
33
+
34
+ # @see RightDevelop::Testing::Server::MightApi::App::Base#handle_request
35
+ def handle_request(env, verb, uri, headers, body)
36
+ proxy(
37
+ ::RightDevelop::Testing::Client::Rest::Request::Record,
38
+ verb,
39
+ uri,
40
+ headers,
41
+ body)
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,8 @@
1
+ lib_dir = ::File.expand_path('../../../../../../lib', __FILE__)
2
+ $:.unshift(lib_dir) unless $:.include?(lib_dir)
3
+
4
+ require ::File.expand_path('../config/init', __FILE__)
5
+ require ::File.expand_path("../app/#{::RightDevelop::Testing::Server::MightApi::Config.mode}", __FILE__)
6
+
7
+ run ::RightDevelop::Testing::Server::MightApi::App.const_get(
8
+ ::RightDevelop::Testing::Server::MightApi::Config.mode.capitalize).new
@@ -0,0 +1,47 @@
1
+ #
2
+ # Copyright (c) 2014 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ # fixup RACK_ENV
24
+ require 'right_develop'
25
+
26
+ require ::File.expand_path('../../lib/config', __FILE__)
27
+ require ::File.expand_path('../../lib/logger', __FILE__)
28
+
29
+ module RightDevelop::Testing::Server::MightApi
30
+
31
+ # attempt to read stdin for configuration or else expect relative file path.
32
+ # note the following .fcntl call returns zero when data is available on $stdin
33
+ config_yaml = ($stdin.tty? || 0 != $stdin.fcntl(::Fcntl::F_GETFL, 0)) ? '' : $stdin.read
34
+ config_hash = config_yaml.empty? ? nil : ::YAML.load(config_yaml)
35
+ if config_hash
36
+ Config.from_hash(config_hash)
37
+ else
38
+ Config.from_file(Config::DEFAULT_CONFIG_PATH)
39
+ end
40
+
41
+ # ensure fixture dir exists as result of configuration for better
42
+ # synchronization of any state file locking.
43
+ ::FileUtils.mkdir_p(Config.fixtures_dir)
44
+
45
+ # ready.
46
+ logger.info("MightApi initialized in #{Config.mode} mode.")
47
+ end
@@ -0,0 +1,204 @@
1
+ #
2
+ # Copyright (c) 2014 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ if ::ENV['RACK_ENV'].to_s.empty?
24
+ ::ENV['RACK_ENV'] = 'development'
25
+ end
26
+
27
+ require 'right_develop/testing/recording/config'
28
+ require 'uri'
29
+
30
+ # define the module hierarchy once so that it can be on a single line hereafter.
31
+ module RightDevelop
32
+ module Testing
33
+ module Server
34
+ module MightApi
35
+ # if only ruby could consume a single line module declaration...
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ module RightDevelop::Testing::Server::MightApi
42
+ class Config
43
+
44
+ # default config path.
45
+ CONFIG_DIR_NAME = 'config'.freeze
46
+ DEFAULT_CONFIG_PATH = ::File.join(CONFIG_DIR_NAME, 'might_deploy.yml').freeze
47
+
48
+ METADATA_CLASS = ::RightDevelop::Testing::Recording::Metadata
49
+ CONFIG_CLASS = ::RightDevelop::Testing::Recording::Config
50
+
51
+ # Loads the config hash from given path or a relative location.
52
+ #
53
+ # @param [String] path to configuration
54
+ #
55
+ # @return [Mash] configuration hash
56
+ #
57
+ # @raise [ArgumentError] on failure to load
58
+ def self.from_file(path, options = nil)
59
+ @config = CONFIG_CLASS.from_file(path, options)
60
+ self
61
+ end
62
+
63
+ # Setup configuration. Defaults to using environment variables for setup due
64
+ # to rackup not allowing custom arguments to be passed on command line.
65
+ #
66
+ # @param [Hash] config as raw configuration data
67
+ #
68
+ # @return [Config] self
69
+ #
70
+ # @raise [ArgumentError] on failure to load
71
+ def self.from_hash(config_hash)
72
+ @config = CONFIG_CLASS.new(config_hash)
73
+ self
74
+ end
75
+
76
+ # @see Object#method_missing
77
+ def self.method_missing(methud, *args, &block)
78
+ if @config && @config.respond_to?(methud)
79
+ @config.__send__(methud, *args, &block)
80
+ else
81
+ super
82
+ end
83
+ end
84
+
85
+ # @see Object#respond_to?
86
+ def self.respond_to?(methud)
87
+ super(methud) || (@config && @config.respond_to?(methud))
88
+ end
89
+
90
+ # @see Class.const_missing
91
+ def self.const_missing(konst)
92
+ if CONFIG_CLASS.const_defined?(konst)
93
+ CONFIG_CLASS.const_get(konst)
94
+ else
95
+ super
96
+ end
97
+ end
98
+
99
+ # @see Class.const_defined?
100
+ def self.const_defined?(konst)
101
+ super(konst) || CONFIG_CLASS.const_defined?(konst)
102
+ end
103
+
104
+ # @return [String] environment configuration string
105
+ def self.environment
106
+ @environment ||= ::ENV['RACK_ENV']
107
+ end
108
+
109
+ def self.normalize_fixtures_dir(logger)
110
+ # remove any residual state files at root of fixtures directory.
111
+ logger.info("Normalizing fixtures directory: #{fixtures_dir.inspect} ...")
112
+ ::Dir[::File.join(fixtures_dir, '*.yml')].each do |path|
113
+ ::File.unlink(path) if ::File.file?(path)
114
+ end
115
+
116
+ # recursively iterate requests/responses ensuring that both files exist
117
+ # and that they are MD5-named. if not, then supply the MD5 by renaming
118
+ # both files. this allows a user to write custom request/responses without
119
+ # having to supply the MD5 checksum for the significant request parts.
120
+ ::Dir[::File.join(fixtures_dir, '*/*')].sort.each do |epoch_api_dir|
121
+ if ::File.directory?(epoch_api_dir)
122
+ # request/response pairs must be identical whether or not using human-
123
+ # readable file names.
124
+ route_subdir_name = ::File.basename(epoch_api_dir)
125
+ if route = routes.find { |prefix, data| data[:subdir] == route_subdir_name }
126
+ route_path, route_data = route
127
+ requests_dir = epoch_api_dir + '/request/'
128
+ responses_dir = epoch_api_dir + '/response/'
129
+ request_files = ::Dir[requests_dir + '**/*.yml'].sort.map { |path| path[requests_dir.length..-1] }
130
+ response_files = ::Dir[responses_dir + '**/*.yml'].sort.map { |path| path[responses_dir.length..-1] }
131
+ if request_files != response_files
132
+ difference = ((request_files - response_files) | (response_files - request_files)).sort
133
+ message = 'Mismatched request/response file pairs under ' +
134
+ "#{epoch_api_dir.inspect}: #{difference.inspect}"
135
+ raise ::ArgumentError, message
136
+ end
137
+
138
+ # convert filename prefix to MD5 wherever necessary.
139
+ request_files.each do |path|
140
+ # load request/response pair to validate.
141
+ request_file_path = ::File.join(requests_dir, path)
142
+ response_file_path = ::File.join(responses_dir, path)
143
+ request_data = ::Mash.new(::YAML.load_file(request_file_path))
144
+ response_data = ::Mash.new(::YAML.load_file(response_file_path))
145
+
146
+ # if confing contains unreachable (i.e. no available route) files
147
+ # then that is ignorable.
148
+ query_string = request_data[:query]
149
+ uri = METADATA_CLASS.normalize_uri(
150
+ URI::HTTP.build(
151
+ host: 'none',
152
+ path: (route_path + ::File.dirname(path)),
153
+ query: request_data[:query]).to_s)
154
+
155
+ # compute checksum from recorded request metadata.
156
+ request_metadata = METADATA_CLASS.new(
157
+ mode: :echo,
158
+ kind: :request,
159
+ logger: logger,
160
+ route_data: route_data,
161
+ uri: uri,
162
+ verb: request_data[:verb],
163
+ headers: request_data[:headers],
164
+ body: request_data[:body],
165
+ variables: {})
166
+
167
+ # rename fixure file prefix only if given custom name by user.
168
+ name = ::File.basename(path)
169
+
170
+ if matched = FIXTURE_FILE_NAME_REGEX.match(name)
171
+ # verify correct MD5 for body.
172
+ file_checksum = matched[1]
173
+ if file_checksum.casecmp(request_metadata.checksum) != 0
174
+ message = "Checksum from fixture file name (#{file_checksum}) " +
175
+ "does not match the request body checksum " +
176
+ "(#{request_metadata.checksum}): #{request_file_path.inspect}"
177
+ raise ::ArgumentError, message
178
+ end
179
+ else
180
+ # compute checksum from loaded request body.
181
+ checksum_file_name = request_metadata.checksum + '.yml'
182
+
183
+ # rename file pair.
184
+ to_request_file_path = ::File.join(::File.dirname(request_file_path), checksum_file_name)
185
+ to_response_file_path = ::File.join(::File.dirname(response_file_path), checksum_file_name)
186
+ logger.debug("Renaming #{request_file_path.inspect} to #{to_request_file_path.inspect}.")
187
+ ::File.rename(request_file_path, to_request_file_path)
188
+ logger.debug("Renaming #{response_file_path.inspect} to #{to_response_file_path.inspect}.")
189
+ ::File.rename(response_file_path, to_response_file_path)
190
+ end
191
+ end
192
+ else
193
+ # unknown route fixture directories will cause playback engine to
194
+ # spin forever.
195
+ unrecognized_routes << epoch_api_dir
196
+ message = "Cannot find a route for fixtures directory: #{epoch_api_dir.inspect}"
197
+ raise ::ArgumentError, message
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ end # Config
204
+ end # RightDevelop::Testing::Server::MightApi
@@ -0,0 +1,68 @@
1
+ #
2
+ # Copyright (c) 2014 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'logger'
24
+ require 'right_support'
25
+
26
+ module RightDevelop::Testing::Server::MightApi
27
+
28
+ def self.logger
29
+ @logger ||= lambda do
30
+ l = nil
31
+ case Config.environment
32
+ when 'development'
33
+ # file
34
+ log_dir = Config.log_dir
35
+ log_file_path = ::File.join(log_dir, 'development.log')
36
+ ::FileUtils.mkdir_p(log_dir)
37
+ log_file = ::File.open(log_file_path, 'a')
38
+ log_file.sync = true
39
+ file_logger = Logger.new(log_file)
40
+
41
+ # console
42
+ STDOUT.sync = true
43
+ console_logger = ::Logger.new(STDOUT)
44
+
45
+ # multiplexer
46
+ l = ::RightSupport::Log::Multiplexer.new(file_logger, console_logger)
47
+ when 'test'
48
+ # any tests should mock logger to verify output.
49
+ l = ::RightSupport::Log::NullLogger.new
50
+ else
51
+ l = ::RightSupport::Log::SystemLogger.new('might_api', facility: 'local0')
52
+ end
53
+ l.formatter = DateTimeLoggerFormatter.new
54
+ l.level = Config.log_level
55
+ l
56
+ end.call
57
+ end
58
+
59
+ class DateTimeLoggerFormatter < ::Logger::Formatter
60
+ def call(severity, time, progname, msg)
61
+ sprintf("%s (%s) %s: %s\n",
62
+ ::Time.now,
63
+ ::Thread.current.object_id,
64
+ severity,
65
+ msg2str(msg))
66
+ end
67
+ end
68
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{right_develop}
8
- s.version = "2.1.5"
8
+ s.version = "2.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tony Spataro"]
12
- s.date = %q{2014-04-14}
12
+ s.date = %q{2014-04-28}
13
13
  s.default_executable = %q{right_develop}
14
14
  s.description = %q{A toolkit of development tools created by RightScale.}
15
15
  s.email = %q{support@rightscale.com}
@@ -33,6 +33,7 @@ Gem::Specification.new do |s|
33
33
  "lib/right_develop/ci/util.rb",
34
34
  "lib/right_develop/commands.rb",
35
35
  "lib/right_develop/commands/git.rb",
36
+ "lib/right_develop/commands/server.rb",
36
37
  "lib/right_develop/git.rb",
37
38
  "lib/right_develop/git/rake_task.rb",
38
39
  "lib/right_develop/net.rb",
@@ -42,6 +43,27 @@ Gem::Specification.new do |s|
42
43
  "lib/right_develop/s3.rb",
43
44
  "lib/right_develop/s3/interface.rb",
44
45
  "lib/right_develop/s3/rake_task.rb",
46
+ "lib/right_develop/testing.rb",
47
+ "lib/right_develop/testing/clients.rb",
48
+ "lib/right_develop/testing/clients/rest.rb",
49
+ "lib/right_develop/testing/clients/rest/requests.rb",
50
+ "lib/right_develop/testing/clients/rest/requests/base.rb",
51
+ "lib/right_develop/testing/clients/rest/requests/playback.rb",
52
+ "lib/right_develop/testing/clients/rest/requests/record.rb",
53
+ "lib/right_develop/testing/recording.rb",
54
+ "lib/right_develop/testing/recording/config.rb",
55
+ "lib/right_develop/testing/recording/metadata.rb",
56
+ "lib/right_develop/testing/servers/might_api/.gitignore",
57
+ "lib/right_develop/testing/servers/might_api/Gemfile",
58
+ "lib/right_develop/testing/servers/might_api/Gemfile.lock",
59
+ "lib/right_develop/testing/servers/might_api/app/base.rb",
60
+ "lib/right_develop/testing/servers/might_api/app/echo.rb",
61
+ "lib/right_develop/testing/servers/might_api/app/playback.rb",
62
+ "lib/right_develop/testing/servers/might_api/app/record.rb",
63
+ "lib/right_develop/testing/servers/might_api/config.ru",
64
+ "lib/right_develop/testing/servers/might_api/config/init.rb",
65
+ "lib/right_develop/testing/servers/might_api/lib/config.rb",
66
+ "lib/right_develop/testing/servers/might_api/lib/logger.rb",
45
67
  "lib/right_develop/utility.rb",
46
68
  "lib/right_develop/utility/git.rb",
47
69
  "lib/right_develop/utility/shell.rb",
@@ -68,6 +90,8 @@ Gem::Specification.new do |s|
68
90
  s.add_runtime_dependency(%q<trollop>, [">= 1.0", "< 3.0"])
69
91
  s.add_runtime_dependency(%q<right_git>, ["~> 0.1.0"])
70
92
  s.add_runtime_dependency(%q<right_aws>, [">= 2.1.0"])
93
+ s.add_runtime_dependency(%q<extlib>, [">= 0"])
94
+ s.add_runtime_dependency(%q<rack>, [">= 0"])
71
95
  s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
72
96
  s.add_development_dependency(%q<rdoc>, [">= 2.4.2"])
73
97
  else
@@ -79,6 +103,8 @@ Gem::Specification.new do |s|
79
103
  s.add_dependency(%q<trollop>, [">= 1.0", "< 3.0"])
80
104
  s.add_dependency(%q<right_git>, ["~> 0.1.0"])
81
105
  s.add_dependency(%q<right_aws>, [">= 2.1.0"])
106
+ s.add_dependency(%q<extlib>, [">= 0"])
107
+ s.add_dependency(%q<rack>, [">= 0"])
82
108
  s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
83
109
  s.add_dependency(%q<rdoc>, [">= 2.4.2"])
84
110
  end
@@ -91,6 +117,8 @@ Gem::Specification.new do |s|
91
117
  s.add_dependency(%q<trollop>, [">= 1.0", "< 3.0"])
92
118
  s.add_dependency(%q<right_git>, ["~> 0.1.0"])
93
119
  s.add_dependency(%q<right_aws>, [">= 2.1.0"])
120
+ s.add_dependency(%q<extlib>, [">= 0"])
121
+ s.add_dependency(%q<rack>, [">= 0"])
94
122
  s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
95
123
  s.add_dependency(%q<rdoc>, [">= 2.4.2"])
96
124
  end