bruter 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2011 by Ted Kimble
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,222 @@
1
+ # Bruter
2
+
3
+ Bruter is a miniature Ruby library that allows its bearer the ability to craft elegant Rack-based web applications with ease. Bruter stands on the backs of giants:
4
+
5
+ * Servers interface with Bruter -- a [Rack][rack]-compatible application -- with minimal configuration
6
+ * Variably named paths are routed to their proper destination by [HttpRouter][http_router]
7
+ * Dynamic assets -- Sass, LESS, CoffeeScript and more -- are compiled and served by [Sprockets][sprockets]
8
+ * Views and templates are rendered as one by [Mustache][mustache]
9
+
10
+ Surely under 200 lines of code without comments, Bruter is meant to be easy to understand and use. But do not underestimate Bruter's small footprint: Bruter's role lies in its ability to delegate responsibility and provide an intuitive syntax.
11
+
12
+ ## Example
13
+
14
+ Bruter can be found hiding in the usual places.
15
+
16
+ `gem install bruter`
17
+
18
+ You'll need to create a Rackup file.
19
+
20
+ ```ruby
21
+ # config.ru
22
+ require 'bruter'
23
+ $:.unshift File.dirname(__FILE__)
24
+ require 'app/application'
25
+ require 'app/views/hello' # Note that you need to require any files you'll reference, including views
26
+
27
+ run Application.new
28
+ ```
29
+
30
+ Routes and asset paths are defined in a subclass of `Bruter::Application`.
31
+
32
+ ```ruby
33
+ # app/application.rb
34
+
35
+ class Application < Bruter::Application
36
+
37
+ serve_assets 'assets' # Asset paths are relative to where the method is called
38
+ get '/hello/:name', to: 'views/hello' # Bruter will look for a Views::Hello class to render
39
+
40
+ end
41
+ ```
42
+
43
+ View classes should subclass `Bruter::Mustache`.
44
+
45
+ ```ruby
46
+ # app/views/hello.rb
47
+
48
+ module Views
49
+ class Hello < Bruter::Mustache
50
+
51
+ def name
52
+ params[:name]
53
+ end
54
+
55
+ end
56
+ end
57
+ ```
58
+
59
+ Bruter's Mustache will automatically look for an accompanying template in `'../templates'` relative to the view class.
60
+
61
+ ```html
62
+ # app/templates/hello.mustache
63
+
64
+ <!DOCTYPE html>
65
+ <html lang="en">
66
+ <head>
67
+ <meta charset="utf-8">
68
+ <title>Hello {{name}}!</title>
69
+ <link rel="stylesheet" href="/stylesheets/application.css">
70
+ </head>
71
+ <body>
72
+ <h1>Bruter kindly welcomes you, {{name}}!</h1>
73
+ <img src="/images/bruter.jpg">
74
+ </body>
75
+ </html>
76
+ ```
77
+
78
+ Place `'bruter.jpg'` in `'app/assets/images'` and a stylesheet of your preferred format in `'app/assets/stylesheets'` and Sprockets will take care of the rest.
79
+
80
+ ```css
81
+ # app/assets/stylesheets/application.css.scss
82
+
83
+ body {
84
+ text-align: center
85
+ h1 { font-size: 1.25em; }
86
+ }
87
+ ```
88
+
89
+ Bruter is a Rack application; choose any compatible server.
90
+
91
+ `rackup config.ru`
92
+
93
+ ## Routing
94
+
95
+ Routing is handled by HttpRouter. Most applications will subclass `Bruter::Application` and generate routes by calling the class method `:add`. The method accepts a path and a hash of options.
96
+
97
+ ```ruby
98
+ add(path, options = {})
99
+ ```
100
+
101
+ Most routes will want to specify a `:to` option. The `:to` option can be any Rack application.
102
+
103
+ ```ruby
104
+ add '/welcome', to: [200, {'Content-Type' => 'text/html'}, ['Welcome to Bruter.']]
105
+ ```
106
+
107
+ Or more interestingly, it can be a string representing a Mustache view class.
108
+
109
+ ```ruby
110
+ add '/welcome', to: 'welcome' # Looks for Welcome
111
+ add '/hello', to: 'views/hello_there' # Looks for Views::HelloThere
112
+ ```
113
+
114
+ The path can include named variables and globs.
115
+
116
+ ```ruby
117
+ add '/hello/:name', to: 'hello' # Matches '/hello/bruter' and '/hello/ted'
118
+ add '/tagged/*tags', to: 'tagged' # Matches '/tagged/web' and '/tagged/volcano/lava/dinosaurs'
119
+ ```
120
+
121
+ Routes can be restricted to certain HTTP request methods.
122
+
123
+ ```ruby
124
+ add '/post/:id', to: 'posts/show', request_method: ['GET', 'HEAD']
125
+ ```
126
+
127
+ Routes can be named in order to construct their paths at a later time.
128
+
129
+ ```ruby
130
+ add '/post/:id', to: 'posts/show', name: :post # In a view, calling path(:post, 5) returns '/post/5'
131
+ ```
132
+
133
+ Variable paths can have a regex matching condition placed on them.
134
+
135
+ ```ruby
136
+ add '/:a-plus-:b-equals', to: 'add', matching: {a: /\d+/, b: /\d+/}
137
+ ```
138
+
139
+ ### Redirects
140
+
141
+ Redirects can be added by setting a `:redirect` option instead of a `:to` option.
142
+
143
+ ```ruby
144
+ add '/old-path', redirect: '/new-path'
145
+ ```
146
+
147
+ ### Static Files
148
+
149
+ Static files can be served by the router by setting a `:static` option instead of a `:to` option.
150
+
151
+ ```ruby
152
+ add '/images', static: 'app/images' # Will look for '/images/logo/large.png' in 'app/images/logo/large.png'
153
+ ```
154
+
155
+ ### Convenience Methods
156
+
157
+ Bruter also provides a number of convenience methods that pass to `:add` but first set their `:request_method` option to correspond to the name of the method.
158
+
159
+ ```ruby
160
+ get(path, options = {})
161
+ post(path, options = {})
162
+ put(path, options = {})
163
+ delete(path, options = {})
164
+ head(path, options = {})
165
+ options(path, options = {})
166
+ trace(path, options = {})
167
+ get(path, options = {})
168
+ ```
169
+
170
+ ### Under the Hood
171
+
172
+ When a new `Bruter::Application` object is instantiated, an `HttpRouter` object is also instantiated and any routes added to the application class are added to the router object. This object can also be accessed directly with the `:router` getter method.
173
+
174
+ ```ruby
175
+ app = Bruter::Application.new
176
+ app.router.add('/').to('my_view')
177
+ run app
178
+ ```
179
+
180
+ See [HttpRouter][http_router] for more information.
181
+
182
+ ## Assets
183
+
184
+ Asset compilation and serving is handled by Sprockets. Asset paths can be added to the asset environment with the class method `:serve_assets`. The method accepts a path, which is relative to the location the method is called.
185
+
186
+ ```ruby
187
+ # app/application.rb
188
+ class Application < Bruter::Application
189
+
190
+ serve_assets 'assets'
191
+
192
+ end
193
+ ```
194
+
195
+ This application will compile and serve assets located in `'app/assets'`. For example, a route of `/images/logo.png` will have the asset environment look for a file named `'app/assets/images/logo.png'` and compile (if necessary) and serve it. If it cannot be found, action is passed to the router.
196
+
197
+ Like with `HttpRouter`, a new `Sprockets::Environment` object is instantiated and any asset paths appended to it when a new `Bruter::Application` object is instantiated. This environment can be accessed directly with the `:assets` getter method.
198
+
199
+ ```ruby
200
+ app = Bruter::Application.new
201
+ app.assets.append_path('my/assets/path')
202
+ run app
203
+ ```
204
+
205
+ See [Sprockets][sprockets] for more information.
206
+
207
+ ## Rendering
208
+
209
+ Routes can be directed to Rack-compatible applications or to strings that represent Mustache view classes. When the latter occurs the application will instantiate the view class with three objects -- a Rack request object, a Rack response object, and the Router object -- and call render. The view class can simply subclass from `Mustache`, but it will likely want to subclass `Bruter::Mustache`, itself a subclass of `Mustache`.
210
+
211
+ `Bruter::Mustache` provides a few helpers. First, it tells any subclasses to look for their templates in `'../template'` relative to the view file. It provides an `:initialize` method that accepts the three previously named objects and then attempts to invoke `:setup` if the view has defined it. It provides getter methods to access the Rack request object (`:request`), the Rack response object (`:response`), the Router object (`:router`), the Rack env (`:env`) and the params set during routing (`:params`). It also defines a `:path` method, which accepts the name of a named route and an optional list of arguments to construct a path string.
212
+
213
+ For more information, see [Mustache][mustache].
214
+
215
+ ## License
216
+
217
+ Bruter is Copyright &copy; 2011 by Ted Kimble and distributed under the MIT license; see `LICENSE` for more information.
218
+
219
+ [rack]: https://github.com/rack/rack
220
+ [http_router]: https://github.com/joshbuddy/http_router
221
+ [sprockets]: https://github.com/sstephenson/sprockets
222
+ [mustache]: https://github.com/defunkt/mustache
data/lib/bruter.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'rack'
2
+ require 'http_router'
3
+ require 'sprockets'
4
+ require 'mustache'
5
+ require 'active_support/core_ext/string/inflections'
6
+ require 'bruter/version'
7
+ require 'bruter/router'
8
+ require 'bruter/mustache'
9
+ require 'bruter/application'
@@ -0,0 +1,158 @@
1
+ module Bruter
2
+ class Application
3
+
4
+ class << self
5
+ attr_accessor :_directory, :routes, :asset_paths
6
+
7
+ # Hack to set :_directory to the file location in which this class is
8
+ # subclassed. Those not subclassing Bruter::Mustache in a file may want
9
+ # to explicitly set :_directory.
10
+ def inherited(klass)
11
+ klass._directory = File.dirname(caller.first[/^[^:]+/])
12
+ end
13
+
14
+ # Retrieves the absolute path of the argument path relative to where
15
+ # Bruter::Application was subclassed (:_directory, see above).
16
+ def absolute_path(path)
17
+ File.expand_path(path, _directory)
18
+ end
19
+
20
+ # Ensure that :routes defaults to an array.
21
+ def routes
22
+ @routes ||= []
23
+ end
24
+
25
+ # Ensure that :asset_paths defaults to an array.
26
+ def asset_paths
27
+ @asset_paths ||= []
28
+ end
29
+
30
+ # Adds a route to the application. Accepts the path of the route and a
31
+ # hash of options. The path is required and can include named variables
32
+ # ('/post/:id') and globs ('/tags/*tags').
33
+ #
34
+ # The options hash must include either a :to, :redirect or :static key;
35
+ # the route will not be recognized if none is present. If more than one
36
+ # is present the preceding order of keys will serve as precedence.
37
+ #
38
+ # The :to key should be either a Rack application or a string
39
+ # representing a Mustache view class. (eg 'my_blog/index' =>
40
+ # MyBlog::Index)
41
+ #
42
+ # The :redirect key should be a string representing the new path or
43
+ # url that the route should redirect to.
44
+ #
45
+ # The :static key should be a string representing a path on the file
46
+ # system (relative to where the method was called).
47
+ #
48
+ # Additional options:
49
+ # Add a name to the route (:name => :posts)
50
+ # Add a regex matching condition (:matching => {:id => /\d+/})
51
+ # Add a HTTP method constraint (:request_method => ['POST', 'HEAD'])
52
+ #
53
+ # Examples:
54
+ # add '/', to: 'views/posts/index', name: :posts
55
+ # add '/posts/:id', to: 'views/posts/show', name: :post
56
+ # add '/posts/:id', to: 'views/posts/update', request_method: ['PUT']
57
+ # add '/tags/*tags', to: 'views/posts/tagged', name: :tagged
58
+ #
59
+ # add '/:i/is-an-integer', to: 'views/integer', matching: {i: /\d+/}
60
+ #
61
+ # add '/old-location', redirect: '/new-location'
62
+ # add '/images/*', static: 'images'
63
+ #
64
+ # For more information see the HttpRouter library
65
+ # (https://github.com/joshbuddy/http_router)
66
+ def add(path, options = {})
67
+ routes << {path: path, options: options}
68
+ end
69
+
70
+ # Convenience method setting the :request_method option to 'GET'.
71
+ def get(path, options = {})
72
+ add(path, options.merge(request_method: 'GET'))
73
+ end
74
+
75
+ # Convenience method setting the :request_method option to 'POST'.
76
+ def post(path, options = {})
77
+ add(path, options.merge(request_method: 'POST'))
78
+ end
79
+
80
+ # Convenience method setting the :request_method option to 'PUT'.
81
+ def put(path, options = {})
82
+ add(path, options.merge(request_method: 'PUT'))
83
+ end
84
+
85
+ # Convenience method setting the :request_method option to 'DELETE'.
86
+ def delete(path, options = {})
87
+ add(path, options.merge(request_method: 'DELETE'))
88
+ end
89
+
90
+ # Convenience method setting the :request_method option to 'HEAD'.
91
+ def head(path, options = {})
92
+ add(path, options.merge(request_method: 'HEAD'))
93
+ end
94
+
95
+ # Convenience method setting the :request_method option to 'OPTIONS'.
96
+ def options(path, options = {})
97
+ add(path, options.merge(request_method: 'OPTIONS'))
98
+ end
99
+
100
+ # Convenience method setting the :request_method option to 'TRACE'.
101
+ def trace(path, options = {})
102
+ add(path, options.merge(request_method: 'TRACE'))
103
+ end
104
+
105
+ # Tells the application's asset environment to serve and compile assets
106
+ # in the path argument without passing to the router. The path is
107
+ # relative to where Bruter::Application is subclassed.
108
+ def serve_assets(path)
109
+ asset_paths << path
110
+ end
111
+
112
+ end
113
+
114
+ attr_accessor :router, :assets
115
+
116
+ # Initializing a new Bruter::Application or a subclass of it will
117
+ # instantiate a new Router and Sprockets::Environment and subsequently add
118
+ # all routes to the router and asset paths to the asset environment.
119
+ def initialize
120
+ @router = Router.new
121
+ @assets = Sprockets::Environment.new
122
+ #
123
+ self.class.routes.each do |r|
124
+ path = r[:path]
125
+ options = r[:options]
126
+ to = options.delete(:to)
127
+ redirect = options.delete(:redirect)
128
+ static = options.delete(:static)
129
+ route = @router.add(path)
130
+ if to
131
+ route.to(to)
132
+ elsif redirect
133
+ route.redirect(redirect)
134
+ elsif static
135
+ route.static(self.class.absolute_path(static))
136
+ end
137
+ options.each { |k, v| route.send(k, v) if route.respond_to?(k) }
138
+ end
139
+ #
140
+ self.class.asset_paths.each do |path|
141
+ @assets.append_path(self.class.absolute_path(path))
142
+ end
143
+ end
144
+
145
+ # A call to this application will first check to see if the path is in any
146
+ # of the asset environment's paths. If so, the asset environment will
147
+ # attempt to serve and compile the asset; if not, action is passed to the
148
+ # router.
149
+ def call(env)
150
+ if @assets.find_asset(env['PATH_INFO'].gsub(/\A\//, ''))
151
+ @assets.call(env)
152
+ else
153
+ @router.call(env)
154
+ end
155
+ end
156
+
157
+ end
158
+ end
@@ -0,0 +1,82 @@
1
+ module Bruter
2
+ class Mustache < Mustache
3
+
4
+ class << self
5
+ attr_accessor :_directory
6
+
7
+ # Hack to set :_directory to the file location in which this class is
8
+ # subclassed. Those not subclassing Bruter::Mustache in a file may want
9
+ # to explicitly set :_directory or the @template_path variable with
10
+ # :template_path=(path).
11
+ def inherited(klass)
12
+ klass._directory = File.dirname(caller.first[/^[^:]+/])
13
+ end
14
+
15
+ # Sets the default template path to '../templates' relative to where the
16
+ # this class is subclassed.
17
+ #
18
+ # Example:
19
+ # # in '/path/to/app/views/tagged.rb'
20
+ # module Views
21
+ # class TaggedPosts < Bruter::Mustache
22
+ # puts self.template_path
23
+ # end
24
+ # end
25
+ #
26
+ # => '/path/to/app/templates'
27
+ def template_path
28
+ if _directory
29
+ @template_path ||= File.expand_path('../templates', _directory)
30
+ else
31
+ super
32
+ end
33
+ end
34
+
35
+ # Sets the default template name to an underscored version of the class
36
+ # name.
37
+ #
38
+ # Example:
39
+ # # in '/path/to/app/views/tagged.rb'
40
+ # module Views
41
+ # class TaggedPosts < Bruter::Mustache
42
+ # puts self.template_name
43
+ # puts self.template_file
44
+ # end
45
+ # end
46
+ #
47
+ # => 'tagged_posts'
48
+ # => '/path/to/app/templates/tagged_posts.mustache'
49
+ def template_name
50
+ @template_name ||= self.to_s.underscore.split('/').last
51
+ end
52
+ end
53
+
54
+ attr_reader :request, :response, :router
55
+
56
+ # Sets the Rack request and response objects and the calling router
57
+ # object. Subclasses can define a :setup method that will be invoked after
58
+ # initialization is complete.
59
+ def initialize(request, response, router)
60
+ @request = request
61
+ @response = response
62
+ @router = router
63
+ send :setup if respond_to?(:setup)
64
+ end
65
+
66
+ # Retrieves the Rack request's env.
67
+ def env
68
+ @request.env
69
+ end
70
+
71
+ # Retrieves the params from a name variable or globbed route.
72
+ def params
73
+ env['router.params']
74
+ end
75
+
76
+ # Retrieves the path for a named route given the name and any arguments.
77
+ def path(name, *args)
78
+ args.any? ? router.url(name, *args) : router.url(name)
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,22 @@
1
+ module Bruter
2
+ class Router < HttpRouter
3
+
4
+ # Catches destinations that do not respond to :call(env) and transforms
5
+ # them into a constant, initializes them with Rack request and response
6
+ # objects and the router itself, and invokes :render. The Rack response's
7
+ # body will be set to the result of :render and the response finished.
8
+ def process_destination_path(path, env)
9
+ destination = path.route.dest
10
+ if destination.respond_to?(:call)
11
+ destination.call(env)
12
+ else
13
+ request = ::Rack::Request.new(env)
14
+ response = ::Rack::Response.new
15
+ view = destination.camelize.constantize
16
+ response.body = [view.new(request, response, self).render]
17
+ response.finish
18
+ end
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Bruter
2
+ VERSION = '0.0.2'
3
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bruter
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Ted Kimble
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-10-28 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rack
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 29
29
+ segments:
30
+ - 1
31
+ - 3
32
+ - 3
33
+ version: 1.3.3
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: http_router
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - "="
43
+ - !ruby/object:Gem::Version
44
+ hash: 51
45
+ segments:
46
+ - 0
47
+ - 10
48
+ - 2
49
+ version: 0.10.2
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: sprockets
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - "="
59
+ - !ruby/object:Gem::Version
60
+ hash: 15
61
+ segments:
62
+ - 2
63
+ - 0
64
+ - 0
65
+ version: 2.0.0
66
+ type: :runtime
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: activesupport
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - "="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 3
79
+ - 1
80
+ - 0
81
+ version: 3.1.0
82
+ type: :runtime
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: i18n
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ hash: 3
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ type: :runtime
97
+ version_requirements: *id005
98
+ - !ruby/object:Gem::Dependency
99
+ name: mustache
100
+ prerelease: false
101
+ requirement: &id006 !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ~>
105
+ - !ruby/object:Gem::Version
106
+ hash: 411
107
+ segments:
108
+ - 0
109
+ - 99
110
+ - 4
111
+ version: 0.99.4
112
+ type: :runtime
113
+ version_requirements: *id006
114
+ description: Bruter is a miniature Ruby library that allows its bearer the ability to craft elegant Rack-based web applications with ease.
115
+ email: ted@kimble.co
116
+ executables: []
117
+
118
+ extensions: []
119
+
120
+ extra_rdoc_files: []
121
+
122
+ files:
123
+ - README.md
124
+ - LICENSE
125
+ - lib/bruter/application.rb
126
+ - lib/bruter/mustache.rb
127
+ - lib/bruter/router.rb
128
+ - lib/bruter/version.rb
129
+ - lib/bruter.rb
130
+ homepage: https://github.com/tedkimble/bruter
131
+ licenses: []
132
+
133
+ post_install_message:
134
+ rdoc_options: []
135
+
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ hash: 55
144
+ segments:
145
+ - 1
146
+ - 9
147
+ - 2
148
+ version: 1.9.2
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ hash: 3
155
+ segments:
156
+ - 0
157
+ version: "0"
158
+ requirements: []
159
+
160
+ rubyforge_project: bruter
161
+ rubygems_version: 1.8.6
162
+ signing_key:
163
+ specification_version: 3
164
+ summary: Bruter helps you craft elegant Ruby web applications.
165
+ test_files: []
166
+