nitro 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +14 -4
- data/ChangeLog +192 -1
- data/README +50 -6
- data/RELEASES +60 -0
- data/Rakefile +1 -1
- data/bin/cluster.rb +2 -2
- data/bin/new_form.rb +1 -1
- data/examples/blog/config.rb +5 -4
- data/examples/blog/lib/blog.rb +56 -36
- data/examples/blog/root/comments.xhtml +5 -2
- data/examples/blog/root/entry_form.xhtml +7 -2
- data/examples/blog/root/login.xhtml +1 -1
- data/examples/blog/root/style.xsl +7 -0
- data/examples/og/mock_example.rb +6 -9
- data/examples/og/mysql_to_psql.rb +100 -0
- data/examples/og/run.rb +8 -17
- data/lib/glue.rb +7 -8
- data/lib/glue/array.rb +1 -1
- data/lib/glue/attribute.rb +86 -0
- data/lib/glue/cache.rb +1 -1
- data/lib/glue/hash.rb +1 -1
- data/lib/glue/inflector.rb +1 -1
- data/lib/glue/logger.rb +118 -18
- data/lib/glue/mixins.rb +1 -1
- data/lib/glue/number.rb +1 -1
- data/lib/glue/pool.rb +1 -1
- data/lib/glue/property.rb +48 -31
- data/lib/glue/string.rb +1 -1
- data/lib/glue/time.rb +2 -2
- data/lib/glue/validation.rb +400 -0
- data/lib/nitro/application.rb +6 -6
- data/lib/nitro/builders/form.rb +5 -5
- data/lib/nitro/builders/rss.rb +1 -1
- data/lib/nitro/builders/xhtml.rb +119 -0
- data/lib/nitro/builders/xml.rb +111 -0
- data/lib/nitro/config.rb +6 -6
- data/lib/nitro/events.rb +1 -1
- data/lib/nitro/html.rb +1 -1
- data/lib/nitro/markup.rb +15 -20
- data/lib/nitro/scaffold.rb +2 -2
- data/lib/nitro/server/appserver.rb +3 -3
- data/lib/nitro/server/cluster.rb +2 -2
- data/lib/nitro/server/dispatcher.rb +2 -2
- data/lib/nitro/server/filters/autologin.rb +1 -1
- data/lib/nitro/server/fragment.rb +2 -2
- data/lib/nitro/server/handlers.rb +2 -2
- data/lib/nitro/server/render.rb +17 -15
- data/lib/nitro/server/request.rb +6 -6
- data/lib/nitro/server/script.rb +2 -2
- data/lib/nitro/server/server.rb +2 -2
- data/lib/nitro/server/session.rb +6 -6
- data/lib/nitro/server/shaders.rb +2 -2
- data/lib/nitro/server/webrick.rb +1 -1
- data/lib/nitro/sitemap.rb +2 -2
- data/lib/nitro/uri.rb +1 -1
- data/lib/nitro/version.rb +7 -5
- data/lib/og.rb +95 -129
- data/lib/og/backend.rb +47 -46
- data/lib/og/backends/mysql.rb +64 -63
- data/lib/og/backends/psql.rb +73 -72
- data/lib/og/connection.rb +7 -8
- data/lib/og/enchant.rb +80 -0
- data/lib/og/meta.rb +21 -21
- data/lib/og/mock.rb +31 -88
- data/lib/og/version.rb +6 -5
- data/lib/parts/README +9 -0
- data/lib/parts/content.rb +23 -9
- data/test/glue/tc_attribute.rb +22 -0
- data/test/glue/tc_cache.rb +4 -6
- data/test/glue/tc_hash.rb +2 -2
- data/test/glue/tc_logger.rb +36 -0
- data/test/glue/tc_numbers.rb +2 -2
- data/test/glue/tc_property_mixins.rb +35 -4
- data/test/glue/tc_strings.rb +32 -32
- data/test/glue/tc_validation.rb +186 -0
- data/test/nitro/builders/tc_xhtml.rb +38 -0
- data/test/nitro/builders/tc_xml.rb +47 -0
- data/test/nitro/server/tc_request.rb +2 -2
- data/test/nitro/server/tc_session.rb +1 -1
- data/test/nitro/tc_sitemap.rb +1 -1
- data/test/nitro/ui/tc_pager.rb +1 -10
- data/test/tc_og.rb +3 -3
- data/vendor/blankslate.rb +53 -0
- data/vendor/extensions/_base.rb +153 -0
- data/vendor/extensions/_template.rb +36 -0
- data/vendor/extensions/all.rb +21 -0
- data/vendor/extensions/array.rb +68 -0
- data/vendor/extensions/binding.rb +224 -0
- data/vendor/extensions/class.rb +50 -0
- data/vendor/extensions/continuation.rb +71 -0
- data/vendor/extensions/enumerable.rb +250 -0
- data/vendor/extensions/hash.rb +23 -0
- data/vendor/extensions/io.rb +58 -0
- data/vendor/extensions/kernel.rb +42 -0
- data/vendor/extensions/module.rb +114 -0
- data/vendor/extensions/numeric.rb +230 -0
- data/vendor/extensions/object.rb +164 -0
- data/vendor/extensions/ostruct.rb +41 -0
- data/vendor/extensions/string.rb +316 -0
- data/vendor/extensions/symbol.rb +28 -0
- metadata +35 -13
- data/lib/glue/property.rb.old +0 -307
@@ -0,0 +1,38 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'nitro/builders/xhtml'
|
5
|
+
|
6
|
+
class TC_BuildersXhtml < Test::Unit::TestCase # :nodoc: all
|
7
|
+
|
8
|
+
def test_options
|
9
|
+
x = N::XhtmlString.new
|
10
|
+
options = ['Male', 'Female']
|
11
|
+
x.select(:name => 'sex') do
|
12
|
+
x.options(options, 1)
|
13
|
+
end
|
14
|
+
res = '<select name="sex"><option value="0">Male</option>' +
|
15
|
+
'<option value="1" selected="1">Female</option></select>'
|
16
|
+
assert_equal res, x
|
17
|
+
|
18
|
+
x = N::XhtmlString.new
|
19
|
+
options = ['Male', 'Female']
|
20
|
+
x.select('-- Select sex --', :name => 'sex') do
|
21
|
+
x.options(options, 1)
|
22
|
+
end
|
23
|
+
res = '<select name="sex"><option>-- Select sex --</option>' +
|
24
|
+
'<option value="0">Male</option>' +
|
25
|
+
'<option value="1" selected="1">Female</option></select>'
|
26
|
+
assert_equal res, x
|
27
|
+
|
28
|
+
x = N::XhtmlString.new
|
29
|
+
options = {'Male' => 'm', 'Female' => 'f'}
|
30
|
+
x.select(:name => 'sex') do
|
31
|
+
x.options(options, 'm')
|
32
|
+
end
|
33
|
+
res = '<select name="sex"><option value="m" selected="1">Male</option>' +
|
34
|
+
'<option value="f">Female</option></select>'
|
35
|
+
assert_equal res, x
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'nitro/builders/xml'
|
5
|
+
|
6
|
+
class TC_BuildersXml < Test::Unit::TestCase # :nodoc: all
|
7
|
+
|
8
|
+
def test_string
|
9
|
+
x = N::XmlString.new
|
10
|
+
|
11
|
+
x.start_tag('html').
|
12
|
+
start_tag('title').text('hello').end_tag('title').
|
13
|
+
end_tag('html')
|
14
|
+
|
15
|
+
assert_equal '<html><title>hello</title></html>', x
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_missing
|
19
|
+
x = N::XmlString.new
|
20
|
+
x.b('This is bold')
|
21
|
+
assert_equal '<b>This is bold</b>', x
|
22
|
+
|
23
|
+
x = N::XmlString.new
|
24
|
+
x.a('Navel', :href => 'http://www.navel.gr', :target => '_blank')
|
25
|
+
assert_equal '<a target="_blank" href="http://www.navel.gr">Navel</a>', x
|
26
|
+
|
27
|
+
|
28
|
+
x = N::XmlString.new
|
29
|
+
x.b {
|
30
|
+
x.i 'Hello', :class =>'new'
|
31
|
+
x.p 'Paragraph'
|
32
|
+
}
|
33
|
+
assert_equal '<b><i class="new">Hello</i><p>Paragraph</p></b>', x
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_xml_builder
|
37
|
+
buffer = ''
|
38
|
+
x = N::XmlBuilder.new(buffer)
|
39
|
+
|
40
|
+
x.start_tag('html').
|
41
|
+
start_tag('title').text('hello').end_tag('title').
|
42
|
+
end_tag('html')
|
43
|
+
|
44
|
+
assert_equal '<html><title>hello</title></html>', buffer
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "test/unit"
|
4
4
|
|
5
|
-
require "glue/logger"
|
5
|
+
require "glue/logger"
|
6
6
|
|
7
7
|
require "nitro/server/cookie"
|
8
8
|
require "nitro/server/request"
|
@@ -67,4 +67,4 @@ class TC_Request < Test::Unit::TestCase
|
|
67
67
|
assert_equal(nil, request.get_tx_entity())
|
68
68
|
end
|
69
69
|
|
70
|
-
end
|
70
|
+
end
|
data/test/nitro/tc_sitemap.rb
CHANGED
data/test/nitro/ui/tc_pager.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "test/unit"
|
4
4
|
|
5
|
-
require "glue/logger"
|
5
|
+
require "glue/logger"
|
6
6
|
|
7
7
|
require "og"
|
8
8
|
require "nitro/ui/pager"
|
@@ -22,15 +22,6 @@ end
|
|
22
22
|
class TC_N_UI_Pager < Test::Unit::TestCase
|
23
23
|
|
24
24
|
def setup
|
25
|
-
=begin
|
26
|
-
$og = Og::Database.new(
|
27
|
-
:addres => "localhost",
|
28
|
-
:database => "testdb",
|
29
|
-
:user => "root",
|
30
|
-
# :password => "navelrulez",
|
31
|
-
:connection_count => 2
|
32
|
-
)
|
33
|
-
=end
|
34
25
|
end
|
35
26
|
|
36
27
|
def teardown
|
data/test/tc_og.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#--
|
3
|
+
# Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
|
4
|
+
# All rights reserved.
|
5
|
+
|
6
|
+
# Permission is granted for use, copying, modification, distribution,
|
7
|
+
# and distribution of modified versions of this work as long as the
|
8
|
+
# above copyright notice is included.
|
9
|
+
#++
|
10
|
+
|
11
|
+
module Builder #:nodoc:
|
12
|
+
|
13
|
+
# BlankSlate provides an abstract base class with no predefined
|
14
|
+
# methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
|
15
|
+
# BlankSlate is useful as a base class when writing classes that
|
16
|
+
# depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
|
17
|
+
class BlankSlate #:nodoc:
|
18
|
+
class << self
|
19
|
+
def hide(name)
|
20
|
+
undef_method name if
|
21
|
+
instance_methods.include?(name.to_s) and
|
22
|
+
name !~ /^(__|instance_eval)/
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
instance_methods.each { |m| hide(m) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Since Ruby is very dynamic, methods added to the ancestors of
|
31
|
+
# BlankSlate <em>after BlankSlate is defined</em> will show up in the
|
32
|
+
# list of available BlankSlate methods. We handle this by defining a hook in the Object and Kernel classes that will hide any defined
|
33
|
+
module Kernel #:nodoc:
|
34
|
+
class << self
|
35
|
+
alias_method :blank_slate_method_added, :method_added
|
36
|
+
def method_added(name)
|
37
|
+
blank_slate_method_added(name)
|
38
|
+
return if self != Kernel
|
39
|
+
Builder::BlankSlate.hide(name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Object #:nodoc:
|
45
|
+
class << self
|
46
|
+
alias_method :blank_slate_method_added, :method_added
|
47
|
+
def method_added(name)
|
48
|
+
blank_slate_method_added(name)
|
49
|
+
return if self != Object
|
50
|
+
Builder::BlankSlate.hide(name)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# This file is 'required' by all files that implement standard class
|
4
|
+
# extensions as part of the "Ruby/Extensions" project.
|
5
|
+
#
|
6
|
+
# The "Extensions" project requires 1.8.0 or greater to run, as it is too
|
7
|
+
# much hassle at the moment to consider supporting older versions. That may
|
8
|
+
# one day be implemented if demand is there. One option would be to require
|
9
|
+
# "shim", so that we can assume all 1.8 library methods are implemented.
|
10
|
+
#
|
11
|
+
# This file is only of interest to developers of the package, so no detailed
|
12
|
+
# documentation is included here. However, by way of introduction, this is what
|
13
|
+
# it's all about. Each method that is implemented as part of this package is
|
14
|
+
# done so through a framework implemented in this file. Take the following
|
15
|
+
# simple example:
|
16
|
+
#
|
17
|
+
# ExtensionsProject.implement(Integer, :even?, :instance) do
|
18
|
+
# class Integer
|
19
|
+
# #
|
20
|
+
# # RDoc comments.
|
21
|
+
# #
|
22
|
+
# def even?
|
23
|
+
# self % 2 == 0
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# This purposes of this are as follows:
|
29
|
+
# - if the intended method (in this case IO.write) is already defined,
|
30
|
+
# we don't want to overwrite it (we issue a warning and move on)
|
31
|
+
# - if the intended method is _not_ implemented as a result of the block,
|
32
|
+
# we have not done as we said, and an error is raised
|
33
|
+
# - the ExtensionsProject class gathers information on which methods have
|
34
|
+
# been implemented, making for a very handy command-line reference (+rbxtm+)
|
35
|
+
#
|
36
|
+
# The <tt>ExtensionsProject.implement</tt> method is responsible for ensuring
|
37
|
+
# these are so. It gives us documentation, and some assurance that the
|
38
|
+
# extensions are doing what we say they are doing.
|
39
|
+
#
|
40
|
+
|
41
|
+
# :enddoc:
|
42
|
+
|
43
|
+
#
|
44
|
+
# For what reason does Ruby define Module#methods, Module#instance_methods,
|
45
|
+
# and Module#method_defined?, but not Module#instance_method_defined? ?
|
46
|
+
#
|
47
|
+
# No matter, extending standard classes is the name of the game here.
|
48
|
+
#
|
49
|
+
class Module
|
50
|
+
if Module.method_defined?(:instance_method_defined?)
|
51
|
+
STDERR.puts "Warning: Module#instance_method_defined? already defined; not overwriting"
|
52
|
+
else
|
53
|
+
def instance_method_defined?(_method)
|
54
|
+
instance_methods(true).find { |m| m == _method.to_s }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if Module.method_defined?(:module_method_defined?)
|
59
|
+
STDERR.puts "Warning: Module#module_method_defined? already defined; not overwriting"
|
60
|
+
else
|
61
|
+
def module_method_defined?(_method)
|
62
|
+
singleton_methods(true).find { |m| m == _method.to_s }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
class ExtensionsProject
|
69
|
+
|
70
|
+
class << ExtensionsProject
|
71
|
+
@@extension_methods = []
|
72
|
+
|
73
|
+
#
|
74
|
+
# The list of methods implemented in this project.
|
75
|
+
#
|
76
|
+
def extension_methods
|
77
|
+
@@extension_methods
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Return the name of the project. To be used in error messages, etc., for
|
82
|
+
# consistency.
|
83
|
+
#
|
84
|
+
def project_name
|
85
|
+
"Ruby/Extensions"
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Wraps around the implementation of a method, emitting a warning if the
|
90
|
+
# method is already defined. Returns true to indicate - false to indicate
|
91
|
+
# failure (i.e. method is already defined). Raises an error if the
|
92
|
+
# specified method is not actually implemented by the block.
|
93
|
+
#
|
94
|
+
def implement(_module, _method, _type=:instance)
|
95
|
+
raise "Internal error: #{__FILE__}:#{__LINE__}" unless
|
96
|
+
_module.is_a? Module and
|
97
|
+
_method.is_a? Symbol and
|
98
|
+
_type == :instance or _type == :class or _type == :module
|
99
|
+
|
100
|
+
fullname = _module.to_s + string_rep(_type) + _method.to_s
|
101
|
+
|
102
|
+
if _defined?(_module, _method, _type)
|
103
|
+
STDERR.puts "#{project_name}: #{fullname} is already defined; not overwriting"
|
104
|
+
return false
|
105
|
+
else
|
106
|
+
yield # Perform the block; presumably a method implementation.
|
107
|
+
if _method == :initialize and _type == :instance
|
108
|
+
# Special case; we can't verify this.
|
109
|
+
@@extension_methods<< "#{_module}::new"
|
110
|
+
else
|
111
|
+
unless _defined?(_module, _method, _type)
|
112
|
+
raise "#{project_name}: internal error: was supposed to implement " +
|
113
|
+
"#{fullname}, but it didn't!"
|
114
|
+
end
|
115
|
+
@@extension_methods << fullname
|
116
|
+
end
|
117
|
+
return true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
# See whether the given module implements the given method, taking account
|
123
|
+
# of the type (class/instance) required.
|
124
|
+
def _defined?(_module, _method, _type)
|
125
|
+
case _type
|
126
|
+
when :instance
|
127
|
+
_module.instance_method_defined?(_method) # See definition above.
|
128
|
+
when :class, :module
|
129
|
+
_module.module_method_defined?(_method) # See definition above.
|
130
|
+
end
|
131
|
+
end
|
132
|
+
private :_defined?
|
133
|
+
|
134
|
+
|
135
|
+
# Return the string representation of the given method type.
|
136
|
+
def string_rep(method_type)
|
137
|
+
case method_type
|
138
|
+
when :instance then "#"
|
139
|
+
when :class then "."
|
140
|
+
when :module then "."
|
141
|
+
else
|
142
|
+
nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
private :string_rep
|
146
|
+
end
|
147
|
+
end # class ExtensionsProject
|
148
|
+
|
149
|
+
|
150
|
+
if VERSION < "1.8.0"
|
151
|
+
raise "#{ExtensionsProject.project_name} requires Ruby 1.8.0 at least (for now)"
|
152
|
+
end
|
153
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
# A template for new files in the project; of no interest to end users. An
|
3
|
+
# error will be raised if you +require+ it.
|
4
|
+
#--
|
5
|
+
# :enddoc:
|
6
|
+
#
|
7
|
+
# == extensions/XXX.rb
|
8
|
+
#
|
9
|
+
# Adds methods to the builtin XXX class.
|
10
|
+
#
|
11
|
+
|
12
|
+
raise "Do not load this file!"
|
13
|
+
|
14
|
+
require "extensions/_base"
|
15
|
+
|
16
|
+
#
|
17
|
+
# * Enumerable#build_hash
|
18
|
+
#
|
19
|
+
ExtensionsProject.implement(Enumerable, :build_hash) do
|
20
|
+
module Enumerable
|
21
|
+
#
|
22
|
+
# Like #map/#collect, but it generates a Hash.
|
23
|
+
#
|
24
|
+
# [1,5,11].build_hash { |x| [x, x**2] }
|
25
|
+
# => { 1 => 2, 5 => 25, 11 => 121 }
|
26
|
+
#
|
27
|
+
def build_hash
|
28
|
+
result = {}
|
29
|
+
self.each do |elt|
|
30
|
+
key, value = yield elt
|
31
|
+
result[key] = value
|
32
|
+
end
|
33
|
+
result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# == extensions/all.rb
|
3
|
+
#
|
4
|
+
# Require this file in order to access all of the standard class extensions
|
5
|
+
# available, or require individual extension files to narrow the selection.
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'extensions/array.rb'
|
9
|
+
require 'extensions/binding.rb'
|
10
|
+
require 'extensions/class.rb'
|
11
|
+
require 'extensions/continuation.rb'
|
12
|
+
require 'extensions/enumerable.rb'
|
13
|
+
require 'extensions/hash.rb'
|
14
|
+
require 'extensions/io.rb'
|
15
|
+
require 'extensions/kernel.rb'
|
16
|
+
require 'extensions/module.rb'
|
17
|
+
require 'extensions/numeric.rb'
|
18
|
+
require 'extensions/object.rb'
|
19
|
+
require 'extensions/ostruct.rb'
|
20
|
+
require 'extensions/string.rb'
|
21
|
+
require 'extensions/symbol.rb'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
#
|
3
|
+
# == extensions/array.rb
|
4
|
+
#
|
5
|
+
# Adds methods to the builtin Array class.
|
6
|
+
#
|
7
|
+
|
8
|
+
require "extensions/_base"
|
9
|
+
|
10
|
+
#
|
11
|
+
# * Array#select!
|
12
|
+
#
|
13
|
+
ExtensionsProject.implement(Array, :select!) do
|
14
|
+
class Array
|
15
|
+
#
|
16
|
+
# In-place version of Array#select. (Counterpart to, and opposite of, the
|
17
|
+
# built-in #reject!)
|
18
|
+
#
|
19
|
+
def select!
|
20
|
+
reject! { |e| not yield(e) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
#
|
27
|
+
# * Array#only
|
28
|
+
#
|
29
|
+
ExtensionsProject.implement(Array, :only) do
|
30
|
+
class Array
|
31
|
+
#
|
32
|
+
# Returns the _only_ element in the array. Raises an IndexError if the array's size is not
|
33
|
+
# 1.
|
34
|
+
#
|
35
|
+
# [5].only # -> 5
|
36
|
+
# [1,2,3].only # -> IndexError
|
37
|
+
# [].only # -> IndexError
|
38
|
+
#
|
39
|
+
def only
|
40
|
+
unless size == 1
|
41
|
+
raise IndexError, "Array#only called on non-single-element array"
|
42
|
+
end
|
43
|
+
first
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# * Array#rand
|
50
|
+
#
|
51
|
+
ExtensionsProject.implement(Array, :rand) do
|
52
|
+
class Array
|
53
|
+
#
|
54
|
+
# Return a randomly-chosen (using Kernel.rand) element from the array.
|
55
|
+
#
|
56
|
+
# arr = [48, 71, 3, 39, 15]
|
57
|
+
# arr.rand # -> 71
|
58
|
+
# arr.rand # -> 39
|
59
|
+
# arr.rand # -> 48
|
60
|
+
# # etc.
|
61
|
+
#
|
62
|
+
def rand
|
63
|
+
idx = Kernel.rand(size)
|
64
|
+
at(idx)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|