speck_gem 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem "rack"
4
+ gem "tilt"
5
+ gem "mocha_standalone"
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ metaclass (0.0.1)
5
+ mocha (0.12.3)
6
+ metaclass (~> 0.0.1)
7
+ rack (1.5.2)
8
+ tilt (1.3.6)
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ mocha
15
+ rack
16
+ tilt
data/README.md ADDED
@@ -0,0 +1,99 @@
1
+ Speck
2
+ =====
3
+
4
+ Ruby Microframework.
5
+
6
+ Getting Started
7
+ ===============
8
+ 1. make filesystem seen in app directory
9
+ 2. require gem
10
+
11
+
12
+ Routing
13
+ =======
14
+
15
+ ```ruby
16
+ # routes.rb
17
+
18
+ match '/','Home' do
19
+ get '' => 'index'
20
+ post 'login' => 'authenticate'
21
+ end
22
+
23
+ match '/vacations','Vacation' do
24
+ get '' => 'index', '/:id'=>'show'
25
+ put '/:id' => 'update'
26
+ post '/:id' => 'edit'
27
+
28
+ match '/:id1/photos','Photo' do
29
+ get '' => 'index', '/:id2' => 'show'
30
+ put '/:id2' => 'update'
31
+ post '/:id2' => 'edit'
32
+ end
33
+ end
34
+ ```
35
+
36
+ Controllers
37
+ ===========
38
+ ```ruby
39
+ class Photo < Speck::Controller
40
+ def index
41
+ session[:user] = params[:user]
42
+ render('home.html.erb')
43
+ end
44
+
45
+ def show
46
+ @user = session[:user]
47
+ @photo = fetch_photo(params[:id])
48
+ render('photo.html.erb')
49
+ end
50
+ end
51
+
52
+ ```
53
+
54
+ Templates
55
+ =========
56
+ Speck uses the tilt gem for template rendering. Many templating languages are supported. Below is an example using erb.
57
+ ```html
58
+ <h1><%= @user %></h1>
59
+
60
+ <% @photos.each do |photo| %>
61
+ <% @id = photo.id %>
62
+ <% @location = photo.location %>
63
+ <% @file = photo.file_path %>
64
+ <%= render('photo_partial.html.erb') %>
65
+ <% end %>
66
+
67
+ ```
68
+ and photo_partial.html.erb
69
+ ```html
70
+ <h3><%= @id %></h3>
71
+ <p><%= @location %></p>
72
+ <img src='<%= @file %>' />
73
+ ```
74
+ There are helper functions for paths, javascrpit, and css.
75
+
76
+ App Structure
77
+ =============
78
+ ```
79
+ /app
80
+ /assets
81
+ /controllers
82
+ /views
83
+ config.rb
84
+ exception.html.erb
85
+ Gemfile
86
+ routes.rb
87
+ server.log
88
+ ```
89
+
90
+ Rake Commands
91
+ =============
92
+ * rake test: runs the gem's test suite
93
+
94
+ TODO
95
+ ====
96
+ * test config
97
+ * test session persistence
98
+ * app structure
99
+ * rake task for building app structure
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ task :test do
2
+ require "cutest"
3
+ require "speck"
4
+ require "mocha_standalone"
5
+ Cutest.run(Dir["test/*.rb"]-Dir["test/*_example.rb"])
6
+ end
7
+
8
+ task :default => :test
9
+
10
+ require 'bundler'
11
+ Bundler::GemHelper.install_tasks
data/app/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ gem "speck"
2
+ gem "tilt"
data/app/config.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'speck'
2
+
3
+ Speck::Config.run()
@@ -0,0 +1,2 @@
1
+ <h1><%= @status %></h1>
2
+ <p><%= @message %></p>
data/app/routes.rb ADDED
File without changes
data/app/server.log ADDED
@@ -0,0 +1,5 @@
1
+ # Logfile created on 2013-05-12 23:40:45 -0400 by logger.rb/31641
2
+ E, [2013-05-12T23:40:45.944095 #43403] ERROR -- : [2013-05-12 23:40:45 -0400] 500: Missing rack.input
3
+
4
+ E, [2013-05-12T23:42:06.077617 #43650] ERROR -- : [2013-05-12 23:42:06 -0400] 500: Missing rack.input
5
+
File without changes
@@ -0,0 +1,67 @@
1
+ require 'rack'
2
+
3
+
4
+ module Speck
5
+ class Config
6
+ private_class_method :new
7
+
8
+ def self.app_root
9
+ if Dir.pwd[-3,3] == 'app'
10
+ dir = Dir.pwd
11
+ else
12
+ dir = Dir.pwd+'/app'
13
+ end
14
+ @@app_root ||= dir
15
+ end
16
+
17
+ def self.set_app_root(root)
18
+ @@app_root = root
19
+ end
20
+
21
+ def set_app_server(type)
22
+ @@server = type
23
+ end
24
+
25
+ def self.app_server
26
+ @@server ||= Rack::Handler::WEBrick
27
+ end
28
+
29
+ def self.app_port
30
+ @@port ||= 5000
31
+ end
32
+
33
+ def self.set_app_port(port)
34
+ @@port = port
35
+ end
36
+
37
+ def self.app_middleware
38
+ @@middleware ||= [[Rack::Static,{:urls => ["/assets"]}],
39
+ [Rack::Session::Cookie, {:key => 'rack.session',
40
+ :path => '/',
41
+ :expire_after => 2592000,
42
+ :secret => 'SECRETKEY1111'}]]
43
+ end
44
+
45
+ def self.add_app_middleware(middleware, options)
46
+ nxt = [middleware, options]
47
+ if app_middleware.nil?
48
+ @@middleware = [nxt]
49
+ else
50
+ @@middleware << nxt
51
+ end
52
+ end
53
+
54
+ def self.launch
55
+ app = Rack::Builder.app do
56
+ Speck::Config.app_middleware.each do |middleware|
57
+ use middleware[0], middleware[1]
58
+ end
59
+ Signal.trap('INT') {
60
+ Speck::Config.app_server.shutdown
61
+ }
62
+ run Speck::Router.new
63
+ end
64
+ app_server.run(app, :Port => app_port)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,76 @@
1
+ require 'tilt'
2
+
3
+ module Speck
4
+
5
+ class Controller
6
+
7
+ def initialize(session, params)
8
+ @__session = session
9
+ @__params = params
10
+ end
11
+
12
+ def link(path,text)
13
+ "<a href='#{path}'>#{text}</a>"
14
+ end
15
+
16
+ def asset(filename)
17
+ path('asset',filename)
18
+ end
19
+
20
+ def controller(filename)
21
+ path('controller',filename)
22
+ end
23
+
24
+ def view(filename)
25
+ path('view',filename)
26
+ end
27
+
28
+ def path(type,filename)
29
+ case type
30
+ when /app/
31
+ Config.app_root+'/'+filename
32
+ when /asset/
33
+ '/assets/'+filename
34
+ when /controller/
35
+ Config.app_root+'/controllers/'+filename
36
+ when /view/
37
+ Config.app_root+'/views/'+filename
38
+ else
39
+ message = "#{type} is not a valid type! Valid types are 'app','asset','controller','view'!"
40
+ raise Speck_Exception.new(message)
41
+ end
42
+ end
43
+
44
+ def js(filename)
45
+ if filename =~ /\.js/
46
+ js = path('assets',filename)
47
+ else
48
+ js = path('assets',filename+'.js')
49
+ end
50
+ "<script src='#{js}' type='text/javascript' charset='utf-8'></script>"
51
+ end
52
+
53
+ def css(filename)
54
+ if filename =~ /\.css/
55
+ style = path('assets',filename)
56
+ else
57
+ style = path('assets',filename+'.css')
58
+ end
59
+ "<link rel='STYLESHEET' href='#{style}' type='text/css'>"
60
+ end
61
+
62
+ def render(template_path)
63
+ Log.render(template_path)
64
+ Tilt.new(template_path).render(self)
65
+ end
66
+
67
+ def session
68
+ @__session
69
+ end
70
+
71
+ def params
72
+ @__params
73
+ end
74
+ end
75
+
76
+ end
@@ -0,0 +1,17 @@
1
+ module Speck
2
+ class Speck_Exception < RuntimeError
3
+ end
4
+
5
+ class Routing_Exception < Speck_Exception
6
+ attr_reader :status, :message
7
+
8
+ def initialize(status, message)
9
+ @status = status
10
+ @message = message
11
+ end
12
+
13
+ def render()
14
+ Tilt.new(Config.app_root+'/exception.html.erb').render(self)
15
+ end
16
+ end
17
+ end
data/lib/speck/log.rb ADDED
@@ -0,0 +1,37 @@
1
+ require 'logger'
2
+
3
+ module Speck
4
+ class Log
5
+
6
+ def self.log
7
+ @log ||= Logger.new(Config.app_root+'/server.log', shift_age = 'weekly')
8
+ end
9
+
10
+ def self.render(path)
11
+ write(Logger::INFO, "Renderig: #{path}")
12
+ end
13
+
14
+ def self.request(request)
15
+ write(Logger::INFO,"Starting: #{request.request_method} #{request.fullpath}")
16
+ end
17
+
18
+ def self.dispatch(controller,action,params)
19
+ write(Logger::INFO,"Dispatching: #{controller}.#{action} with #{params}")
20
+ end
21
+
22
+ def self.exception(status,message)
23
+ write(Logger::WARN,"#{status}: #{message}")
24
+ end
25
+
26
+ def self.error(error)
27
+ puts error.backtrace
28
+ write(Logger::ERROR,"500: #{error.message}")
29
+ end
30
+
31
+ def self.write(severity,msg)
32
+ out = "[#{Time.now}] #{msg}\n"
33
+ puts out
34
+ log.add(severity,message=out)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,115 @@
1
+ require 'rack'
2
+ require 'speck/controller'
3
+ require 'speck/log'
4
+ require 'speck/exception'
5
+ require 'speck/config'
6
+
7
+ Dir[Speck::Config.app_root+"/controllers/*.rb"].each {|file| require file }
8
+
9
+
10
+ module Speck
11
+ class Router
12
+
13
+ attr_reader :routes
14
+
15
+ @@HTTP_REQUESTS = [:GET, :PUT, :POST, :DELETE]
16
+
17
+ def initialize(path=nil)
18
+ @routes = {}
19
+ @controller = []
20
+ @base = ''
21
+ @@HTTP_REQUESTS.each{ |req| @routes[req] = {}}
22
+ build_routes(path)
23
+ end
24
+
25
+ def build_routes(path=nil)
26
+ path ||= Config.app_root+'/routes.rb'
27
+ instance_eval(File.read(path))
28
+ end
29
+
30
+ def match(base,controller, &block)
31
+ @base << base
32
+ @controller << controller
33
+ instance_eval(&block)
34
+ @controller.pop()
35
+ @base.chomp!(base)
36
+ end
37
+
38
+ def call(env)
39
+ @request = Rack::Request.new(env)
40
+ @response = process
41
+ @response.finish
42
+ end
43
+
44
+ def symbolize_keys(hash)
45
+ hash.keys.each do |key|
46
+ hash[(key.to_sym rescue key) || key] = hash.delete(key)
47
+ end
48
+ hash
49
+ end
50
+
51
+ def controller_action_params
52
+ routes = @routes[@request.request_method.to_sym]
53
+ valid_routes = routes.keys.select{ |route| matching? route}
54
+ raise Routing_Exception.new(404,'Page not found!') if valid_routes.empty?
55
+ controller, action = routes[valid_routes.first]
56
+ params = extract_params(valid_routes.first)
57
+ params.merge!(symbolize_keys(@request.params)) if @request.form_data?
58
+ [controller, action, params]
59
+ end
60
+
61
+ def matching?(route)
62
+ route_list = route.split('/')
63
+ path_list = @request.path.split('/')
64
+ return false unless path_list.length == route_list.length
65
+ path_list.length.times { |i| return false unless route_list[i][0] == ":" or route_list[i] == path_list[i]}
66
+ true
67
+ end
68
+
69
+ def extract_params(route)
70
+ route_list = route.split('/')
71
+ path_list = @request.path.split('/')
72
+
73
+ params = {}
74
+ path_list.length.times do |i|
75
+ params[route_list[i].sub(":","").to_sym] = path_list[i] if route_list[i][0] == ":"
76
+ end
77
+ params
78
+ end
79
+
80
+ def process
81
+ Log.request(@request)
82
+ begin
83
+ controller, action, params = controller_action_params
84
+ Log.dispatch(controller,action,params)
85
+ session = @request.env['rack.session']
86
+ session[:init] = true #forces session loading
87
+ body = Kernel.const_get(controller).new(session|| {}, params).send(action)
88
+ status = 200
89
+ rescue Routing_Exception => ex
90
+ Log.exception(ex.status, ex.message)
91
+ body = ex.render
92
+ status = ex.status
93
+ rescue RuntimeError => e
94
+ Log.error(e)
95
+ ex = Routing_Exception.new(500,'Server Error!')
96
+ body = ex.render
97
+ status = 500
98
+ end
99
+ resp = Rack::Response.new(body=body, status=status)
100
+ end
101
+
102
+ def add_route(request_type, bindings)
103
+ bindings.each { |route, action| @routes[request_type][@base+route] = [@controller.last,action] }
104
+ end
105
+
106
+ def method_missing(name, *args, &block)
107
+ if @@HTTP_REQUESTS.include?(name.upcase)
108
+ add_route(name.upcase,args[0])
109
+ else
110
+ super(name, *args, &block)
111
+ end
112
+ end
113
+
114
+ end
115
+ end
data/lib/speck.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'speck/log'
2
+ require 'speck/router'
3
+ require 'speck/controller'
4
+ require 'speck/config'
data/server.log ADDED
@@ -0,0 +1 @@
1
+ # Logfile created on 2013-05-12 22:35:54 -0400 by logger.rb/31641
data/speck.gemspec ADDED
@@ -0,0 +1,10 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'speck_gem'
3
+ s.version = '1.0.0'
4
+ s.date = '2013-04-06'
5
+ s.summary = "See documentation"
6
+ s.description = "A simple ruby web framework"
7
+ s.authors = ["David Thomas"]
8
+ s.email = 'davidthomas5412@gmail.com'
9
+ s.files = `git ls-files`.split("\n") - %w[.gitignore]
10
+ end
data/test/config.rb ADDED
File without changes
@@ -0,0 +1,51 @@
1
+ require 'speck'
2
+
3
+ class Location < Speck::Controller
4
+ def index
5
+ "index called"
6
+ end
7
+
8
+ def show
9
+ "id: #{params[:id]}"
10
+ end
11
+
12
+ def template
13
+ @msg = 'template message'
14
+ render('test/template_example.html.erb')
15
+ end
16
+
17
+ def template_with_partial
18
+ @title = "template title"
19
+ @body = "partial body"
20
+ render('test/template2_example.html.erb')
21
+ end
22
+ end
23
+
24
+ class Book < Speck::Controller
25
+ def show
26
+ "id: #{params[:id]}"
27
+ end
28
+ end
29
+
30
+
31
+ class Home < Speck::Controller
32
+ def index
33
+ "index body"
34
+ end
35
+
36
+ def authenticate
37
+ raise RuntimeError
38
+ end
39
+ end
40
+
41
+ class Vacation < Speck::Controller
42
+ def show
43
+ "id: #{params[:id]}"
44
+ end
45
+ end
46
+
47
+ class Photo < Speck::Controller
48
+ def show
49
+ "id1: #{params[:id1]} id2: #{params[:id2]}"
50
+ end
51
+ end
@@ -0,0 +1,60 @@
1
+ require File.dirname(File.expand_path(__FILE__))+'/controller_example.rb'
2
+
3
+ def assert_contain(actual, expected)
4
+ actual =~ expected
5
+ end
6
+
7
+ setup do
8
+ Speck::Log.stubs(:render)
9
+ end
10
+
11
+ test "controller dispatching actions" do
12
+ assert_equal Location.new({},{}).send('index'), "index called"
13
+ assert_equal Location.new({},{:id => 99}).send('show'), "id: 99"
14
+ end
15
+
16
+ test "controller rendering with instance variables" do
17
+ assert_contain Location.new({},{}).send('template'), /template message/
18
+ end
19
+
20
+ test "controller classes don't share param state" do
21
+ assert_equal Location.new({},{:id => 0}).send('show'), "id: 0"
22
+ assert_equal Book.new({},{:id => 1}).send('show'), "id: 1"
23
+ end
24
+
25
+ test "recursive rendering of partials" do
26
+ assert_contain Location.new({},{}).send('template_with_partial'), /template title/
27
+ assert_contain Location.new({},{}).send('template_with_partial'), /partial body/
28
+ end
29
+
30
+ test "session persists accross requests" do
31
+ end
32
+
33
+ test "path" do
34
+ loc = Location.new({},{})
35
+ root = Speck::Config.app_root
36
+ assert_equal loc.path('app','config.rb'), root+'/config.rb'
37
+ assert_equal loc.path('views','photo.html.erb'), root+'/views/photo.html.erb'
38
+ assert_equal loc.path('asset','jquery.js'), '/assets/jquery.js'
39
+ end
40
+
41
+ test "invalid path raises speck exception" do
42
+ loc = Location.new({},{})
43
+ assert_raise Speck::Speck_Exception do
44
+ loc.path('veew','')
45
+ end
46
+ end
47
+
48
+ test "javascript helper" do
49
+ loc = Location.new({},{})
50
+ root = Speck::Config.app_root
51
+ expected = "<script src='/assets/jquery.js' type='text/javascript' charset='utf-8'></script>"
52
+ assert_equal loc.js('jquery'), expected
53
+ end
54
+
55
+ test "css helper" do
56
+ loc = Location.new({},{})
57
+ root = Speck::Config.app_root
58
+ expected = "<link rel='STYLESHEET' href='/assets/style.css' type='text/css'>"
59
+ assert_equal loc.css('style'), expected
60
+ end
data/test/exception.rb ADDED
@@ -0,0 +1,11 @@
1
+ setup do
2
+ Speck::Config.set_app_root('app')
3
+ end
4
+
5
+ test "404 routing exception" do
6
+ ex = Speck::Routing_Exception.new(404,'Page not found!')
7
+ assert_equal ex.status, 404
8
+ assert_equal ex.message, 'Page not found!'
9
+ assert_equal ex.render, "<h1>404</h1>
10
+ <p>Page not found!</p>"
11
+ end
data/test/logger.rb ADDED
@@ -0,0 +1,7 @@
1
+ test "logger is singleton" do
2
+ initial_log = Speck::Log.log
3
+ initial_log.expects(:add)
4
+ Speck::Log.expects(:write)
5
+ Speck::Log.dispatch("controller","acton","params")
6
+ assert_equal Speck::Log.log, initial_log
7
+ end
@@ -0,0 +1 @@
1
+ <%= @body %>
data/test/router.rb ADDED
@@ -0,0 +1,66 @@
1
+ test = File.dirname(File.expand_path(__FILE__))
2
+ require test+'/controller_example.rb'
3
+
4
+ ### To test response
5
+ module Rack
6
+ class Response
7
+ attr_reader :body
8
+ end
9
+ end
10
+
11
+ def expect_request
12
+ Speck::Log.expects(:request)
13
+ Speck::Log.expects(:dispatch)
14
+ end
15
+
16
+ def test_response(r,env,status,body)
17
+ expect_request
18
+ env['rack.session'] ={}
19
+ resp = r.call(env)
20
+ assert_equal resp[2].body(), [body]
21
+ assert_equal resp[0], status
22
+ end
23
+
24
+ setup do
25
+ Speck::Router.new(test+'/routes_example.rb')
26
+ end
27
+
28
+ test 'routes controller action' do |r|
29
+ assert_equal r.routes[:GET]['/'], ['Home','index']
30
+ assert_equal r.routes[:POST]['/login'], ['Home','authenticate']
31
+ end
32
+
33
+ test 'nested routes' do |r|
34
+ assert_equal r.routes[:GET]['/vacations/:id1/photos'], ['Photo','index']
35
+ end
36
+
37
+ test 'route with param' do |r|
38
+ assert_equal r.routes[:PUT]['/vacations/:id'], ['Vacation','update']
39
+ end
40
+
41
+ test 'handle example request' do |r|
42
+ env = {"PATH_INFO"=>"/", "REQUEST_METHOD"=>"GET"}
43
+ test_response(r,env,200,"index body")
44
+ end
45
+
46
+ test 'handle exmple request with parameters' do |r|
47
+ env = {"PATH_INFO"=>"/vacations/99", "REQUEST_METHOD"=>"GET"}
48
+ test_response(r,env,200,"id: 99")
49
+ end
50
+
51
+ test 'handle nested route request with multiple parameters' do |r|
52
+ env = {"PATH_INFO"=>"/vacations/1/photos/2", "REQUEST_METHOD"=>"GET"}
53
+ test_response(r,env,200,"id1: 1 id2: 2")
54
+ end
55
+
56
+ test 'handle 404' do |r|
57
+ env = {"PATH_INFO"=>"facebook", "REQUEST_METHOD"=>"GET"}
58
+ Speck::Log.expects(:exception)
59
+ test_response(r,env,404,"<h1>404</h1>\n<p>Page not found!</p>")
60
+ end
61
+
62
+ test 'handle 500' do |r|
63
+ env = {"PATH_INFO"=>"/login", "REQUEST_METHOD"=>"POST"}
64
+ Speck::Log.expects(:error)
65
+ test_response(r,env,500,"<h1>500</h1>\n<p>Server Error!</p>")
66
+ end
@@ -0,0 +1,16 @@
1
+ match '/','Home' do
2
+ get '' => 'index'
3
+ post 'login' => 'authenticate'
4
+ end
5
+
6
+ match '/vacations','Vacation' do
7
+ get '' => 'index', '/:id'=>'show'
8
+ put '/:id' => 'update'
9
+ post '/:id' => 'edit'
10
+
11
+ match '/:id1/photos','Photo' do
12
+ get '' => 'index', '/:id2' => 'show'
13
+ put '/:id2' => 'update'
14
+ post '/:id2' => 'edit'
15
+ end
16
+ end
@@ -0,0 +1,2 @@
1
+ <h1><%= @title %></h1>
2
+ <p><%= render('test/partial_example.html.erb') %></p>
@@ -0,0 +1 @@
1
+ <p><%= @message %></p>
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: speck_gem
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - David Thomas
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-06 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A simple ruby web framework
15
+ email: davidthomas5412@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - Gemfile
21
+ - Gemfile.lock
22
+ - README.md
23
+ - Rakefile
24
+ - app/Gemfile
25
+ - app/config.rb
26
+ - app/exception.html.erb
27
+ - app/routes.rb
28
+ - app/server.log
29
+ - app/server.log.20130511
30
+ - lib/speck.rb
31
+ - lib/speck/config.rb
32
+ - lib/speck/controller.rb
33
+ - lib/speck/exception.rb
34
+ - lib/speck/log.rb
35
+ - lib/speck/router.rb
36
+ - server.log
37
+ - speck.gemspec
38
+ - test/config.rb
39
+ - test/controller_example.rb
40
+ - test/controllers.rb
41
+ - test/exception.rb
42
+ - test/logger.rb
43
+ - test/partial_example.html.erb
44
+ - test/router.rb
45
+ - test/routes_example.rb
46
+ - test/template2_example.html.erb
47
+ - test/template_example.html.erb
48
+ homepage:
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 1.8.24
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: See documentation
72
+ test_files: []