rails_runner 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 140270f54be56b6eb841de14c8d0b6489c3ad786
4
+ data.tar.gz: e93221ca8696a833cad6421d2a30d6ccca1f805f
5
+ SHA512:
6
+ metadata.gz: 336638f0a7e7bdde650884ef05d823ea2633a09ba7c2735ec03e8fe2a2f875f95559895130ad6a5d3932f86e78cae38bd10b715ff6527fa1e100b3c669f5ef31
7
+ data.tar.gz: 96e042ca7425e45c388de5ffa75f94ae081e7a78c7efbc58495cbc7a8f3945cf16ca3419f8cf5aa978b66a61c914b6fba49c0f6186ec67f30120c6fc57bb545b
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = RailsRunner
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'RailsRunner'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
@@ -0,0 +1,54 @@
1
+ require 'socket'
2
+
3
+ module RailsRunner
4
+ class Config
5
+ class ConfigurationMissing < StandardError
6
+ def initialize(filename)
7
+ @filename = filename
8
+ end
9
+
10
+ def message(*args)
11
+ "Please make sure the configuration file exists: #{@filename}"
12
+ end
13
+ end
14
+
15
+ def initialize(config_file)
16
+ @config_file = config_file
17
+ load_config
18
+ end
19
+
20
+ def load_config
21
+ raise ConfigurationMissing.new(@config_file) unless File.exist?(@config_file)
22
+ file = YAML.load(File.read(@config_file))
23
+ if file && file[env]
24
+ @configuration = file[env].with_indifferent_access
25
+ else
26
+ @configuration = {}
27
+ end
28
+ end
29
+
30
+ def collector_url
31
+ @configuration[:collector_url] ||= 'http://www.railsrunner.com'
32
+ end
33
+
34
+ def client_id
35
+ @configuration[:client_id]
36
+ end
37
+
38
+ def app_name
39
+ @configuration[:app_name] ||= Rails.application.class.parent_name
40
+ end
41
+
42
+ def active?
43
+ @configuration[:active] ||= !%w(test development).include?(env)
44
+ end
45
+
46
+ def hostname
47
+ @hostname ||= Socket.gethostname
48
+ end
49
+
50
+ def env
51
+ ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,47 @@
1
+ module RailsRunner
2
+ class Instrumenter
3
+ MUTEX = Mutex.new
4
+
5
+ class << self
6
+ def current_request
7
+ Thread.current[:rails_runner_current_request]
8
+ end
9
+
10
+ def current_request=(request)
11
+ Thread.current[:rails_runner_current_request] = request
12
+ end
13
+
14
+ def start!
15
+ return @instance if @instance
16
+
17
+ MUTEX.synchronize do
18
+ return @instance if @instance
19
+ @instance = new.start
20
+ end
21
+ end
22
+
23
+ def instance
24
+ @instance
25
+ end
26
+ end
27
+
28
+ def start
29
+ @worker = Worker.start!
30
+ @subscriber = Subscriber.new.register
31
+
32
+ self
33
+ end
34
+
35
+ def record(*args)
36
+ self.class.current_request = Request.new
37
+ end
38
+
39
+ def reset
40
+ self.class.current_request = nil
41
+ end
42
+
43
+ def publish(request)
44
+ @worker.push(request)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,25 @@
1
+ module RailsRunner
2
+ class Action
3
+ include Beefcake::Message
4
+
5
+ required :category, :string, 1
6
+ required :object, :string, 2
7
+ required :start, :int64, 3
8
+ required :end, :int64, 4
9
+ required :duration, :int64, 5
10
+ required :explain, :string, 6
11
+ required :level, :int32, 7
12
+
13
+ def initialize(category, object, explain = '')
14
+ @category = category
15
+ @object = object
16
+ @explain = explain.to_s
17
+ @start = Util.time_in_usec
18
+ end
19
+
20
+ def finish
21
+ @end = Util.time_in_usec
22
+ @duration = @end - @start
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ module RailsRunner
2
+ class Batch
3
+ include Beefcake::Message
4
+
5
+ required :client_id, :string, 1
6
+ required :app_name, :string, 2
7
+ required :hostname, :string, 3
8
+
9
+ repeated :minutes, Minute, 5
10
+
11
+ def initialize
12
+ @client_id = RailsRunner.config.client_id
13
+ @app_name = RailsRunner.config.app_name
14
+ @hostname = RailsRunner.config.hostname
15
+
16
+ @_minutes = {}
17
+ end
18
+
19
+ def current_minute
20
+ @_minutes[minute] ||= RailsRunner::Minute.new(minute)
21
+ end
22
+
23
+ def encode(*)
24
+ @minutes = @_minutes.values
25
+ super
26
+ end
27
+
28
+ def minutes
29
+ @minutes ||= @_minutes.values
30
+ end
31
+
32
+ private
33
+
34
+ def minute
35
+ Time.now.to_i / 60
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ module RailsRunner
2
+ class Endpoint
3
+ include Beefcake::Message
4
+ required :name, :string, 1
5
+ required :errors, :int64, 2
6
+ repeated :times, :int64, 3, packed: true
7
+ repeated :counts, :int64, 4, packed: true
8
+
9
+ def initialize(*args)
10
+ super
11
+ @errors = 0
12
+ @times = Hash.new { |h, k| h[k] = 0 }
13
+ end
14
+
15
+ def add_time(time)
16
+ @times[time.to_i] += 1
17
+ end
18
+
19
+ def add_error
20
+ @errors += 1
21
+ end
22
+
23
+ def times
24
+ @times.keys
25
+ end
26
+
27
+ def counts
28
+ @times.values
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,80 @@
1
+ module RailsRunner
2
+ class Minute
3
+ include Beefcake::Message
4
+
5
+ required :minute, :int64, 1
6
+ repeated :endpoints, Endpoint, 2, packed: true
7
+ repeated :traces, Request, 3, packed: true
8
+
9
+ def initialize(minute = Time.now.to_i)
10
+ @minute = minute
11
+ @errors = 0
12
+ @endpoints = {}
13
+ @trace_endpoints = {}
14
+ end
15
+
16
+ def add_request(request)
17
+ add_error(request)
18
+
19
+ add_time(request)
20
+
21
+ add_trace(request)
22
+ end
23
+
24
+ def add_trace(request)
25
+ return if request.traceable?
26
+ return if slower_request_registered?(request)
27
+ @trace_endpoints[request.name] = request
28
+ end
29
+
30
+ def add_time(request)
31
+ time = rounded(request.duration)
32
+ endpoint(request.name).add_time(time) if request.name.present?
33
+ endpoint('total').add_time(time)
34
+ end
35
+
36
+ def traces
37
+ @trace_endpoints.values
38
+ end
39
+
40
+ def add_error(request)
41
+ return unless request.error?
42
+ endpoint(request.name || 'total').add_error
43
+ end
44
+
45
+ def endpoints
46
+ @endpoints.values
47
+ end
48
+
49
+ private
50
+
51
+ def endpoint(name)
52
+ @endpoints[name] ||= Endpoint.new(name: name)
53
+ end
54
+
55
+ def rounded(duration)
56
+ if duration < 500_000
57
+ mod = 10_000
58
+ elsif duration < 1000_000
59
+ mod = 50_000
60
+ elsif duration < 1500_000
61
+ mod = 100_000
62
+ elsif duration < 2250_000
63
+ mod = 150_000
64
+ elsif duration < 3000_000
65
+ mod = 200_000
66
+ else
67
+ return 3000_000
68
+ end
69
+ duration - (duration % mod)
70
+ end
71
+
72
+ def slower_request_registered?(request)
73
+ if @trace_endpoints[request.name]
74
+ @trace_endpoints[request.name].duration > request.duration
75
+ else
76
+ false
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,48 @@
1
+ module RailsRunner
2
+ class Request
3
+ include Beefcake::Message
4
+
5
+ optional :name, :string, 1
6
+ required :start, :int64, 2
7
+ required :end, :int64, 3
8
+ required :duration, :int64, 4
9
+ required :error, :bool, 5
10
+ repeated :actions, Action, 6, packed: true
11
+
12
+ attr_accessor :notifications
13
+
14
+ def initialize
15
+ @start = Util.time_in_usec
16
+ @current_level = 0
17
+ @actions = []
18
+ @notifications = []
19
+ end
20
+
21
+ def finish(error = false)
22
+ @end = Util.time_in_usec
23
+ @duration = @end - @start
24
+ @error = error
25
+ Instrumenter.instance.publish(self)
26
+ end
27
+
28
+ def add_action(action)
29
+ action.level = @current_level
30
+ @current_level += 1
31
+ @actions << action
32
+ end
33
+
34
+ def finish_action(action)
35
+ return unless action
36
+ action.finish
37
+ @current_level -= 1
38
+ end
39
+
40
+ def traceable?
41
+ name.blank? || error?
42
+ end
43
+
44
+ def error?
45
+ @error
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ module RailsRunner
2
+ class Middleware
3
+ def initialize(app)
4
+ @app = app
5
+ end
6
+
7
+ def call(env)
8
+ begin
9
+ request = instrumenter.record 'Rack', 'rack.request'
10
+ resp = @app.call(env)
11
+ request.finish if request
12
+ resp
13
+ rescue Exception
14
+ request.finish(true) if request
15
+ raise
16
+ ensure
17
+ instrumenter.reset
18
+ end
19
+ end
20
+
21
+ def instrumenter
22
+ RailsRunner::Instrumenter.instance
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,42 @@
1
+ module RailsRunner
2
+ class Notifications
3
+ class Default
4
+ class << self
5
+ def notification(name)
6
+ RailsRunner::Notifications.add_notification(name, self)
7
+ end
8
+ end
9
+
10
+ def to_action(request, payload)
11
+ nil #
12
+ end
13
+ end
14
+
15
+ class RenderDefault < Default
16
+ class << self
17
+ def mapped_paths
18
+ return @mapped_paths if @mapped_paths
19
+ @mapped_paths = {
20
+ Rails.root.to_s => ''
21
+ }
22
+ Gem.path.each do |path|
23
+ @mapped_paths[File.join(path, 'gems')] = 'gem'
24
+ end if defined?(Gem)
25
+
26
+ @mapped_paths
27
+ end
28
+
29
+ def prune_path(raw_path)
30
+ mapped_paths.each do |path, replacement|
31
+ raw_path = raw_path.gsub(path, replacement)
32
+ end
33
+ raw_path
34
+ end
35
+ end
36
+
37
+ def prune_path(path)
38
+ self.class.prune_path(path)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ module RailsRunner
2
+ class Notifications
3
+ class ProcessAction < Default
4
+ notification 'process_action.action_controller'
5
+
6
+ def to_action(request, payload)
7
+ request.name = "#{payload[:controller]}##{payload[:action]}"
8
+ Action.new('Controller', request.name)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module RailsRunner
2
+ class Notifications
3
+ class RenderPartial < RenderDefault
4
+ notification 'render_partial.action_view'
5
+
6
+ def to_action(request, payload)
7
+ Action.new('View', prune_path(payload[:identifier]))
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module RailsRunner
2
+ class Notifications
3
+ class RenderTemplate < RenderDefault
4
+ notification 'render_template.action_view'
5
+
6
+ def to_action(request, payload)
7
+ Action.new('View', prune_path(payload[:identifier]))
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module RailsRunner
2
+ class Notifications
3
+ class Sql < Default
4
+ IGNORED_NAMES = %w(SCHEMA EXPLAIN CACHE) << nil
5
+
6
+ notification 'sql.active_record'
7
+
8
+ def to_action(request, payload)
9
+ return if IGNORED_NAMES.include? payload[:name]
10
+ Action.new('Database', payload[:name], payload[:sql])
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ module RailsRunner
2
+ class Notifications
3
+ class << self
4
+ DEFAULT_NOTIFICATION = Default.new
5
+
6
+ def add_notification(name, notification)
7
+ @notifications ||= {}
8
+ @notifications[name] = notification.new
9
+ end
10
+
11
+ def to_action(request, name, payload)
12
+ notification = @notifications[name] || DEFAULT_NOTIFICATION
13
+ notification.to_action(request, payload)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module RailsRunner
2
+ class Railtie < Rails::Railtie
3
+ initializer 'rails_runner.configure' do |app|
4
+ Instrumenter.start!
5
+ app.middleware.insert 0, Middleware
6
+ RailsRunner.config = RailsRunner::Config.new(app.root.join('config/railsrunner.yml'))
7
+
8
+ puts "[RAILSRUNNER] started"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ module RailsRunner
2
+ class Subscriber
3
+ Notification = Struct.new(:name, :action)
4
+
5
+ def register
6
+ unregister if @subscriber
7
+ @subscriber = ActiveSupport::Notifications.subscribe nil, self
8
+ end
9
+
10
+ def start(name, id, payload)
11
+ request = Instrumenter.current_request
12
+ return unless request
13
+
14
+ if (action = Notifications.to_action(request, name, payload))
15
+ request.add_action(action)
16
+ end
17
+
18
+ request.notifications << Notification.new(name, action)
19
+ end
20
+
21
+ def finish(name, id, payload)
22
+ request = Instrumenter.current_request
23
+ return unless request
24
+
25
+ while (notification = request.notifications.pop)
26
+ if notification.name == name
27
+ request.finish_action(notification.action)
28
+ return
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,31 @@
1
+ require 'zlib'
2
+ require 'base64'
3
+
4
+ module RailsRunner
5
+ class Util
6
+ class << self
7
+ def time_in_usec(time = Time.now)
8
+ time.to_i * 1_000_000 + time.usec
9
+ end
10
+
11
+ def post(body)
12
+ uri = URI.parse(URI.join("#{RailsRunner.config.collector_url}").to_s)
13
+ http = Net::HTTP.new(uri.host, uri.port)
14
+ gzipped = Base64.encode64(gzip(body))
15
+
16
+ request = Net::HTTP::Post.new(uri.request_uri)
17
+ request.body = gzipped
18
+ request['Authorization'] = "#{RailsRunner.config.client_id}"
19
+
20
+ http.request(request)
21
+ end
22
+
23
+ def gzip(bytes)
24
+ gz = Zlib::GzipWriter.new(buffer = StringIO.new)
25
+ gz.write(bytes)
26
+ gz.close
27
+ buffer.string
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module RailsRunner
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,59 @@
1
+ module RailsRunner
2
+ class Worker
3
+ MUTEX = Mutex.new
4
+
5
+ attr_accessor :requests, :batch
6
+
7
+ class << self
8
+ def start!
9
+ return if @instance
10
+ MUTEX.synchronize do
11
+ return @instance if @instance
12
+ @instance = new.start
13
+ end
14
+ end
15
+
16
+ def instance
17
+ @instance
18
+ end
19
+ end
20
+
21
+ def initialize
22
+ @queue = Queue.new
23
+ @requests = 0
24
+ @batch = Batch.new
25
+ end
26
+
27
+ def start
28
+ Thread.new do
29
+ while (request = @queue.pop)
30
+ begin
31
+ case request
32
+ when Request
33
+ batch.current_minute.add_request(request)
34
+ @requests += 1
35
+ when :flush
36
+ send_to_collector
37
+ end
38
+ rescue Exception => e
39
+ puts e.message
40
+ end
41
+ end
42
+ end
43
+ self
44
+ end
45
+
46
+ def push(request)
47
+ @queue << request
48
+ end
49
+
50
+ def send_to_collector
51
+ @batch.encode(buffer = '')
52
+
53
+ Util.post(buffer)
54
+
55
+ @requests = 0
56
+ @batch = Batch.new
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,34 @@
1
+ require 'beefcake'
2
+
3
+ module RailsRunner
4
+ require 'rails_runner/util'
5
+ require 'rails_runner/messages/action'
6
+ require 'rails_runner/messages/endpoint'
7
+ require 'rails_runner/messages/request'
8
+ require 'rails_runner/messages/minute'
9
+ require 'rails_runner/messages/batch'
10
+
11
+ require 'rails_runner/notifications/default'
12
+ require 'rails_runner/notifications'
13
+ require 'rails_runner/notifications/process_action'
14
+ require 'rails_runner/notifications/render_partial'
15
+ require 'rails_runner/notifications/render_template'
16
+ require 'rails_runner/notifications/sql'
17
+
18
+ require 'rails_runner/instrumenter'
19
+ require 'rails_runner/middleware'
20
+ require 'rails_runner/railtie'
21
+ require 'rails_runner/subscriber'
22
+ require 'rails_runner/worker'
23
+ require 'rails_runner/config'
24
+
25
+ def config=(config)
26
+ @config = config
27
+ end
28
+ module_function :config=
29
+
30
+ def config
31
+ @config || RailsRunner::Config.new(Rails.root.join('config/railsrunner.yml'))
32
+ end
33
+ module_function :config
34
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :rails_runner do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_runner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Benoist Claassen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: beefcake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Running rails
56
+ email:
57
+ - benoist.claassen@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - lib/rails_runner/config.rb
63
+ - lib/rails_runner/instrumenter.rb
64
+ - lib/rails_runner/messages/action.rb
65
+ - lib/rails_runner/messages/batch.rb
66
+ - lib/rails_runner/messages/endpoint.rb
67
+ - lib/rails_runner/messages/minute.rb
68
+ - lib/rails_runner/messages/request.rb
69
+ - lib/rails_runner/middleware.rb
70
+ - lib/rails_runner/notifications/default.rb
71
+ - lib/rails_runner/notifications/process_action.rb
72
+ - lib/rails_runner/notifications/render_partial.rb
73
+ - lib/rails_runner/notifications/render_template.rb
74
+ - lib/rails_runner/notifications/sql.rb
75
+ - lib/rails_runner/notifications.rb
76
+ - lib/rails_runner/railtie.rb
77
+ - lib/rails_runner/subscriber.rb
78
+ - lib/rails_runner/util.rb
79
+ - lib/rails_runner/version.rb
80
+ - lib/rails_runner/worker.rb
81
+ - lib/rails_runner.rb
82
+ - lib/tasks/rails_runner_tasks.rake
83
+ - MIT-LICENSE
84
+ - Rakefile
85
+ - README.rdoc
86
+ homepage: http://railsrunner.com
87
+ licenses: []
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.0.3
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Running rails
109
+ test_files: []