nitro 0.9.5 → 0.10.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 (104) hide show
  1. data/ChangeLog +260 -0
  2. data/INSTALL +60 -0
  3. data/LICENSE +1 -0
  4. data/README +19 -20
  5. data/RELEASES +48 -0
  6. data/Rakefile +102 -92
  7. data/benchmark/og/bench.rb +74 -0
  8. data/benchmark/og/sqlite-no-prepare.1.txt +13 -0
  9. data/benchmark/og/sqlite-no-prepare.2.txt +13 -0
  10. data/benchmark/og/sqlite-prepare.1.txt +13 -0
  11. data/benchmark/og/sqlite-prepare.2.txt +13 -0
  12. data/bin/cluster +1 -1
  13. data/bin/nitro +3 -0
  14. data/bin/proto/conf/app.conf.rb +2 -10
  15. data/examples/README.windows +9 -0
  16. data/examples/blog/README +16 -4
  17. data/examples/blog/lib/blog.rb +3 -3
  18. data/examples/blog/lib/blog/controller.rb +7 -9
  19. data/examples/blog/root/fcgi.rb +2 -4
  20. data/examples/blog/root/style.xsl +4 -6
  21. data/examples/blog/run.rb +41 -0
  22. data/examples/flash/run.rb +9 -0
  23. data/examples/no_xsl_blog/README +0 -1
  24. data/examples/no_xsl_blog/conf/app.conf.rb +6 -13
  25. data/examples/no_xsl_blog/lib/blog.rb +2 -2
  26. data/examples/no_xsl_blog/lib/blog/controller.rb +6 -6
  27. data/examples/no_xsl_blog/root/fcgi.rb +2 -4
  28. data/examples/no_xsl_blog/run.rb +38 -0
  29. data/examples/og/mock_example.rb +0 -2
  30. data/examples/og/mysql_to_psql.rb +0 -2
  31. data/examples/og/run.rb +23 -22
  32. data/examples/tiny/root/fcgi.rb +2 -4
  33. data/examples/tiny/root/index.xhtml +21 -5
  34. data/examples/tiny/root/upload.xhtml +23 -0
  35. data/examples/tiny/run.rb +9 -0
  36. data/examples/wee_style/{wee.rb → run.rb} +13 -13
  37. data/install.rb +44 -0
  38. data/lib/glue/array.rb +6 -10
  39. data/lib/glue/attribute.rb +0 -3
  40. data/lib/glue/cache.rb +1 -1
  41. data/lib/glue/inflector.rb +5 -5
  42. data/lib/glue/mixins.rb +3 -12
  43. data/lib/glue/number.rb +1 -1
  44. data/lib/glue/object.rb +7 -1
  45. data/lib/glue/property.rb +32 -22
  46. data/lib/glue/string.rb +13 -75
  47. data/lib/glue/time.rb +2 -2
  48. data/lib/glue/validation.rb +7 -11
  49. data/lib/nitro.rb +16 -1
  50. data/lib/nitro/{adaptors → adapters}/cgi.rb +101 -20
  51. data/lib/nitro/{adaptors → adapters}/fastcgi.rb +3 -2
  52. data/lib/nitro/{adaptors → adapters}/webrick.rb +4 -4
  53. data/lib/nitro/builders/rss.rb +1 -1
  54. data/lib/nitro/builders/xml.rb +8 -10
  55. data/lib/nitro/cluster.rb +1 -1
  56. data/lib/nitro/conf.rb +34 -0
  57. data/lib/nitro/controller.rb +8 -9
  58. data/lib/nitro/dispatcher.rb +38 -11
  59. data/lib/nitro/filters.rb +1 -1
  60. data/lib/nitro/markup.rb +14 -1
  61. data/lib/nitro/render.rb +7 -10
  62. data/lib/nitro/runner.rb +232 -0
  63. data/lib/nitro/ui/pager.rb +2 -6
  64. data/lib/nitro/uri.rb +7 -11
  65. data/lib/og.rb +27 -261
  66. data/lib/og/adapter.rb +352 -0
  67. data/lib/og/adapters/mysql.rb +304 -0
  68. data/lib/og/adapters/psql.rb +286 -0
  69. data/lib/og/adapters/sqlite.rb +262 -0
  70. data/lib/og/backend.rb +1 -1
  71. data/lib/og/connection.rb +123 -87
  72. data/lib/og/database.rb +268 -0
  73. data/lib/og/meta.rb +23 -22
  74. data/lib/og/mock.rb +2 -3
  75. data/lib/xsl/base.xsl +1 -55
  76. data/test/glue/tc_property.rb +2 -0
  77. data/test/glue/tc_property_type_checking.rb +32 -0
  78. data/test/glue/tc_strings.rb +2 -2
  79. data/test/glue/tc_validation.rb +2 -0
  80. data/test/nitro/adapters/raw_post1.bin +0 -0
  81. data/test/nitro/{adaptors → adapters}/tc_cgi.rb +11 -2
  82. data/test/nitro/{adaptors → adapters}/tc_webrick.rb +3 -3
  83. data/test/nitro/builders/tc_xml.rb +14 -5
  84. data/test/nitro/tc_dispatcher.rb +3 -3
  85. data/test/nitro/tc_uri.rb +2 -4
  86. data/test/og/tc_lifecycle.rb +22 -25
  87. data/test/og/tc_sqlite.rb +87 -0
  88. data/test/tc_og.rb +61 -42
  89. metadata +67 -33
  90. data/examples/blog/conf/app.conf.rb +0 -52
  91. data/examples/blog/ctl +0 -4
  92. data/examples/flash/conf/app.conf.rb +0 -21
  93. data/examples/flash/ctl +0 -4
  94. data/examples/no_xsl_blog/conf/apache.conf +0 -0
  95. data/examples/no_xsl_blog/ctl +0 -4
  96. data/examples/tiny/conf/app.conf.rb +0 -17
  97. data/examples/tiny/ctl +0 -4
  98. data/lib/glue/macro.rb +0 -56
  99. data/lib/nitro/adaptors/runner.rb +0 -123
  100. data/lib/nitro/version.rb +0 -15
  101. data/lib/og/backends/mysql.rb +0 -370
  102. data/lib/og/backends/psql.rb +0 -386
  103. data/lib/og/backends/sqlite.rb +0 -383
  104. data/lib/og/version.rb +0 -9
data/Rakefile CHANGED
@@ -2,132 +2,142 @@
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
3
  # $Id$
4
4
 
5
- require "rake"
6
- require "rake/rdoctask"
7
- require "rake/gempackagetask"
8
- require "rake/testtask"
9
- require "rubygems"
5
+ require 'rake/rdoctask'
6
+ require 'rake/testtask'
7
+ require 'rake/gempackagetask'
10
8
 
11
- project = 'nitro'
12
- #project = 'og'
9
+ og = false
13
10
 
14
- # ----------------------------------------------------------------------
15
-
16
- desc "Default Task"
17
11
  task :default => :package
18
12
 
19
- # ----------------------------------------------------------------------
20
-
21
- # Run the tests
13
+ # Run the tests.
22
14
 
23
15
  Rake::TestTask.new do |t|
24
- t.libs << "test"
25
- t.test_files = FileList["test/**/tc*.rb"].exclude("**/tc*og*.rb")
16
+ t.libs << 'test'
17
+ t.test_files = FileList['test/**/tc*.rb'].exclude('**/tc*og*.rb')
26
18
  t.verbose = true
27
19
  end
28
20
 
29
- # Run all tests
21
+ # Run all tests. (including expensive/depended tests)
30
22
 
31
23
  Rake::TestTask.new(:test_all) do |t|
32
- t.libs << "test"
33
- t.test_files = FileList["test/**/tc*.rb"]
24
+ t.libs << 'test'
25
+ t.test_files = FileList['test/**/tc*.rb']
34
26
  t.verbose = true
35
27
  end
36
28
 
37
- # ----------------------------------------------------------------------
29
+ # Generate RDoc documentation.
38
30
 
39
31
  Rake::RDocTask.new do |rd|
40
- rd.main = "README"
41
- rd.rdoc_dir = "rdoc"
42
- rd.rdoc_files.include("README", "lib/**/*.rb")
32
+ rd.main = 'README'
33
+ rd.rdoc_dir = 'rdoc'
34
+ rd.rdoc_files.include('README', 'INSTALL', 'lib/**/*.rb')
35
+ rd.options << '--all --inline-source'
43
36
  end
44
-
45
- # ----------------------------------------------------------------------
46
37
 
47
- if 'nitro' == project
38
+ # Build gem.
39
+
40
+ if og
41
+
42
+ spec = Gem::Specification.new do |s|
43
+ s.name = 'og'
44
+ if File.read('lib/og.rb') =~ /Version\s+=\s+'(\d+\.\d+\.\d+)'/
45
+ s.version = $1
46
+ else
47
+ raise 'No version found'
48
+ end
49
+ s.summary = 'Og (ObjectGraph)'
50
+ s.description = 'An efficient and transparent Object-Relational mapping library'
48
51
 
49
- # Nitro GemSpec
50
- #
51
- require "lib/nitro/version"
52
+ # s.add_dependency 'postgres-pr', '>= 0.3.0'
53
+ # s.add_dependency 'postgres', '>= 0.7.1'
54
+ s.add_dependency 'extensions', '>= 0.5'
55
+ # s.add_dependency 'sqlite3-ruby', '>= 1.0.0'
56
+ #s.add_dependency 'mysql', '>= 2.5.1'
57
+ s.add_dependency 'flexmock', '>= 0.0.3'
58
+
59
+ s.required_ruby_version = '>= 1.8.0'
60
+
61
+ s.files = FileList[
62
+ 'README.og', 'RELEASES.og', 'LICENSE', 'AUTHORS', 'Rakefile', 'ChangeLog*',
63
+ 'install.rb',
64
+ 'examples/og/*', 'lib/glue.rb', 'lib/glue/**/*', 'lib/og/**/*', 'lib/og.rb',
65
+ 'test/*og*.rb', 'test/og/*', 'vendor/extensions/**/*'
66
+ ].exclude('.svn/**/*').exclude('**/*.log').to_a
67
+
68
+ s.require_path = 'lib'
69
+ s.autorequire = 'og'
52
70
 
53
- PKG_VERSION = Nitro::Version
54
- PKG_FILES = FileList[
55
- "[A-Z]*", "{bin,benchmark,etc,ext,examples,doc,lib,test,vendor}/**/*"
56
- # "examples/*.rb"
57
- ].exclude(".svn/**/*").exclude("*.og").exclude("**/*.log")
71
+ s.has_rdoc = true
72
+ s.extra_rdoc_files = FileList['README.og', 'RELEASES.og', 'LICENSE', 'AUTHORS'].to_a
73
+ s.rdoc_options << '--main' << 'README.og' << '--title' << 'Og Documentation'
74
+ s.rdoc_options << '--all' << '--inline-source'
75
+
76
+ s.author = 'George Moschovitis'
77
+ s.email = 'gm@navel.gr'
78
+ s.homepage = 'http://www.rubyforge.com/projects/nitro'
79
+ s.rubyforge_project = 'nitro'
80
+ end
81
+
82
+ else
58
83
 
59
- spec = Gem::Specification.new do |s|
60
- s.name = "nitro"
61
- s.version = PKG_VERSION
62
- s.summary = "Web Engine"
63
- s.description = "An efficient, yet simple engine for Web Applications"
64
- # s.add_dependency("postgres-pr", ">= 0.3.0")
65
- # s.add_dependency("postgres", ">= 0.7.1")
66
- # s.add_dependency("extensions", ">= 0.5")
67
- s.required_ruby_version = ">= 1.8.1"
68
- s.files = PKG_FILES.to_a
69
- s.require_path = "lib"
70
- s.autorequire = "nitro"
71
- s.has_rdoc = true
72
- s.extra_rdoc_files = FileList["[A-Z]*"].exclude("*.og").to_a
73
- s.rdoc_options << "--main" << "README" << "--title" << "Nitro Documentation"
74
- s.test_files = []
75
- s.bindir = "bin"
76
- s.author = "George Moschovitis"
77
- s.email = "gm@navel.gr"
78
- s.homepage = "http://www.navel.gr/nitro"
79
- s.rubyforge_project = "nitro"
84
+ spec = Gem::Specification.new do |s|
85
+ s.name = 'nitro'
86
+ if File.read('lib/nitro.rb') =~ /Version\s+=\s+'(\d+\.\d+\.\d+)'/
87
+ s.version = $1
88
+ else
89
+ raise 'No version found'
80
90
  end
91
+ s.summary = 'Nitro Web Engine'
92
+ s.description =
93
+ 'An efficient, multiparadigm and flexible platform for rapid ' +
94
+ 'web application development. Implements a full development stack ' +
95
+ '(Model, View, Controller).'
96
+
97
+ # s.add_dependency 'postgres-pr', '>= 0.3.0'
98
+ # s.add_dependency 'postgres', '>= 0.7.1'
99
+ s.add_dependency 'extensions', '>= 0.5'
100
+ # s.add_dependency 'sqlite3-ruby', '>= 1.0.0'
101
+ # s.add_dependency 'mysql', '>= 2.5.1'
102
+ s.add_dependency 'flexmock', '>= 0.0.3'
81
103
 
82
- else
104
+ s.required_ruby_version = '>= 1.8.0'
105
+
106
+ s.files = FileList[
107
+ '[A-Z]*', 'install.rb', '{bin,benchmark,examples,doc,lib,test,vendor}/**/*'
108
+ ].exclude('.svn/**/*').exclude('*.og').exclude('**/*.log').to_a
83
109
 
84
- # Og stand-alone GemSpec
85
- #
86
- require "lib/og/version"
110
+ s.require_path = 'lib'
111
+ s.autorequire = 'nitro'
87
112
 
88
- PKG_VERSION = Og::Version
89
- PKG_FILES = FileList[
90
- "README.og", "RELEASES.og", "LICENSE", "AUTHORS", "Rakefile", "ChangeLog*",
91
- "examples/og/*", "lib/glue.rb", "lib/glue/**/*", "lib/og/**/*", "lib/og.rb",
92
- "test/*og*.rb", "test/og/*", "vendor/extensions/**/*"
93
- ].exclude(".svn/**/*").exclude("**/*.log")
113
+ s.has_rdoc = true
114
+ s.extra_rdoc_files = FileList['[A-Z]*'].exclude('*.og').to_a
115
+ s.rdoc_options << '--main' << 'README' << '--title' << 'Nitro Documentation'
116
+ s.rdoc_options << '--all' << '--inline-source'
117
+
118
+ s.test_files = []
94
119
 
95
- spec = Gem::Specification.new do |s|
96
- s.name = 'og'
97
- s.version = PKG_VERSION
98
- s.summary = 'Og (ObjectGraph)'
99
- s.description = 'An efficient and transparent Object-Relational mapping library'
100
- # s.add_dependency("postgres", ">= 0.7.1")
101
- # s.add_dependency("extensions", ">= 0.5")
102
- # s.add_dependency("builder")
103
- s.required_ruby_version = ">= 1.8.1"
104
- s.files = PKG_FILES.to_a
105
- s.require_path = "lib"
106
- s.autorequire = "og"
107
- s.has_rdoc = true
108
- s.extra_rdoc_files = FileList["README.og", "RELEASES.og", "LICENSE", "AUTHORS"].to_a
109
- s.rdoc_options << "--main" << "README.og" << "--title" << "Og Documentation"
110
- s.test_files = []
111
- s.bindir = "bin"
112
- s.author = "George Moschovitis"
113
- s.email = "gm@navel.gr"
114
- s.homepage = "http://www.navel.gr/og"
115
- s.rubyforge_project = "nitro"
116
- end
120
+ s.bindir = 'bin'
121
+ s.executables = ['nitro']
122
+ s.default_executable = 'nitro'
123
+
124
+ s.author = 'George Moschovitis'
125
+ s.email = 'gm@navel.gr'
126
+ s.homepage = 'http://www.rubyforge.com/projects/nitro'
127
+ s.rubyforge_project = 'nitro'
128
+ end
117
129
 
118
130
  end
119
131
 
120
132
  Rake::GemPackageTask.new(spec) do |pkg|
121
- pkg.package_dir = "dist"
133
+ pkg.package_dir = 'dist'
122
134
  pkg.need_zip = true
123
135
  pkg.need_tar = true
124
136
  end
125
137
 
126
- # ----------------------------------------------------------------------
138
+ # Manual install (not recommended).
127
139
 
128
- desc "Install the gem"
129
- task :install => :repackage do
130
- sh "gem install --local --no-rdoc dist/nitro-#{PKG_VERSION}.gem"
140
+ task :install do
141
+ ruby 'install.rb'
131
142
  end
132
143
 
133
- # vim: ft=ruby
@@ -0,0 +1,74 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: bench.rb 255 2005-02-10 12:45:32Z gmosx $
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
6
+
7
+ require 'og'
8
+
9
+ GC.disable
10
+
11
+ config = {
12
+ :adapter => 'sqlite',
13
+ :database => 'test',
14
+ :connection_count => 5
15
+ }
16
+
17
+ class Article
18
+ prop_accessor :title, String
19
+ prop_accessor :body, String
20
+ prop_accessor :hits, Fixnum
21
+ prop_accessor :rate, Fixnum
22
+
23
+ def initialize(title = nil, body = nil)
24
+ @title = title
25
+ @body = body
26
+ @hits = rand(5)
27
+ @rate = rand(100)
28
+ end
29
+ end
30
+
31
+ Og::Database.drop_db!(config)
32
+ db = Og::Database.new(config)
33
+
34
+ # Benchmark the insert speed. Useful for finding
35
+ # the improvement when using prepared statements.
36
+
37
+ articles = []
38
+
39
+ 500.times do |i|
40
+ articles << Article.new("Title#{i}", "Body#{i}")
41
+ end
42
+
43
+ sum = 0
44
+ min = 999999
45
+ max = -min
46
+
47
+ 10.times do |i|
48
+
49
+ db.exec "DELETE FROM #{Article::DBTABLE}"
50
+
51
+ for article in articles
52
+ article.oid = nil
53
+ end
54
+
55
+ Article.create("Dummy", "Dummy")
56
+
57
+ t1 = Time.now
58
+ articles.each do |a|
59
+ a.save!
60
+ end
61
+ t2 = Time.now
62
+
63
+ d = t2 - t1
64
+ sum += d
65
+ min = d if d < min
66
+ max = d if d > max
67
+
68
+ puts "Insert test #{i}: #{d} seconds"
69
+
70
+ end
71
+
72
+ puts "Min: #{min}"
73
+ puts "Max: #{max}"
74
+ puts "Average: #{sum/10}"
@@ -0,0 +1,13 @@
1
+ Insert test 0: 3.53403 seconds
2
+ Insert test 1: 4.222878 seconds
3
+ Insert test 2: 3.84379 seconds
4
+ Insert test 3: 3.877513 seconds
5
+ Insert test 4: 3.793392 seconds
6
+ Insert test 5: 3.725927 seconds
7
+ Insert test 6: 3.814542 seconds
8
+ Insert test 7: 3.760054 seconds
9
+ Insert test 8: 3.936868 seconds
10
+ Insert test 9: 4.061833 seconds
11
+ Min: 3.53403
12
+ Max: 4.222878
13
+ Average: 3.8570827
@@ -0,0 +1,13 @@
1
+ Insert test 0: 4.050384 seconds
2
+ Insert test 1: 4.098912 seconds
3
+ Insert test 2: 3.739213 seconds
4
+ Insert test 3: 4.030227 seconds
5
+ Insert test 4: 4.061516 seconds
6
+ Insert test 5: 3.963748 seconds
7
+ Insert test 6: 4.088462 seconds
8
+ Insert test 7: 4.047734 seconds
9
+ Insert test 8: 3.966496 seconds
10
+ Insert test 9: 3.948346 seconds
11
+ Min: 3.739213
12
+ Max: 4.098912
13
+ Average: 3.9995038
@@ -0,0 +1,13 @@
1
+ Insert test 0: 3.578891 seconds
2
+ Insert test 1: 4.257714 seconds
3
+ Insert test 2: 3.535036 seconds
4
+ Insert test 3: 3.742329 seconds
5
+ Insert test 4: 3.874829 seconds
6
+ Insert test 5: 3.608657 seconds
7
+ Insert test 6: 3.843804 seconds
8
+ Insert test 7: 3.688756 seconds
9
+ Insert test 8: 3.858303 seconds
10
+ Insert test 9: 3.739155 seconds
11
+ Min: 3.535036
12
+ Max: 4.257714
13
+ Average: 3.7727474
@@ -0,0 +1,13 @@
1
+ Insert test 0: 3.859916 seconds
2
+ Insert test 1: 4.321912 seconds
3
+ Insert test 2: 3.836067 seconds
4
+ Insert test 3: 4.077798 seconds
5
+ Insert test 4: 4.171512 seconds
6
+ Insert test 5: 4.148027 seconds
7
+ Insert test 6: 3.841498 seconds
8
+ Insert test 7: 3.94367 seconds
9
+ Insert test 8: 3.758128 seconds
10
+ Insert test 9: 4.25072 seconds
11
+ Min: 3.758128
12
+ Max: 4.321912
13
+ Average: 4.0209248
data/bin/cluster CHANGED
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: cluster.rb 234 2005-01-27 13:01:40Z gmosx $
3
+ # $Id: cluster.rb 249 2005-02-04 14:03:00Z gmosx $
4
4
 
5
5
  # WARNING: This is old code, not updated to work in the
6
6
  # latest nitro release. Will be fixed ASAP.
data/bin/nitro ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ puts 'Not implemented!'
@@ -1,22 +1,14 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: app.rb 197 2004-12-21 13:50:17Z gmosx $
4
-
5
- $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
3
+ # $Id$
6
4
 
7
5
  # $DBG = true
8
6
 
9
7
  require 'nitro'
10
8
  require 'nitro/session'
11
9
 
12
- # gmosx, FIXME: make this default!
13
-
14
- require 'ostruct'
15
-
16
- conf = {
10
+ $conf = {
17
11
  :host => 'localhost',
18
12
  :port => 8080,
19
13
  :dispatcher => N::Dispatcher.new
20
14
  }
21
-
22
- $conf = OpenStruct.new(conf)
@@ -0,0 +1,9 @@
1
+ = Windows
2
+
3
+ If you are running under windows, first run the
4
+ tiny, og, wee_style and no_xsl_blog examples. The blog
5
+ example needs special libraries that are harder to
6
+ setup under Windows.
7
+
8
+ The example no_xsl_blog is a stripped down version
9
+ of the blog example without xsl support.
data/examples/blog/README CHANGED
@@ -6,6 +6,9 @@ A simple blog.
6
6
 
7
7
  Edit the configuration files in conf/* as needed.
8
8
 
9
+ You can also edit the application configuration parameters
10
+ in run.rb.
11
+
9
12
  Dont forget to set your name and the password in the
10
13
  lib/blog.rb file:
11
14
 
@@ -20,7 +23,7 @@ and LIVE configurations.
20
23
 
21
24
  Exec the following command:
22
25
 
23
- ruby ctl
26
+ $ ruby run.rb
24
27
 
25
28
  then point your browser to:
26
29
 
@@ -39,9 +42,18 @@ And start adding blog entries :)
39
42
 
40
43
  The bulk of the code is in the file lib/blog.rb.
41
44
  If you want to modify the example it is a nice idea to switch
42
- to debug mode. Edit the following line in the file app.rb:
45
+ to debug mode. Just run the application in debug mode
46
+ to enable autoreloading of actions/templates and extra
47
+ debugging information.
43
48
 
44
- $DBG = true
49
+ $ ruby run.rb --debug
45
50
 
46
51
  In debug mode the view files (xhtml/xsl/etc) are automatically
47
- reloaded.
52
+ reloaded. The controller classes are also relaoded.
53
+
54
+ You can also attach to a running instance of the blog application
55
+ using irb. Just open a new window and issue the following
56
+ command:
57
+
58
+ $ ruby run.rb --console
59
+