extlib 0.9.8 → 0.9.9
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.
Potentially problematic release.
This version of extlib might be problematic. Click here for more details.
- data/History.txt +22 -0
- data/LICENSE +1 -1
- data/README +0 -0
- data/Rakefile +17 -12
- data/lib/extlib.rb +1 -1
- data/lib/extlib/blank.rb +51 -21
- data/lib/extlib/boolean.rb +1 -1
- data/lib/extlib/class.rb +12 -12
- data/lib/extlib/datetime.rb +20 -2
- data/lib/extlib/dictionary.rb +2 -2
- data/lib/extlib/hash.rb +57 -34
- data/lib/extlib/inflection.rb +0 -1
- data/lib/extlib/lazy_array.rb +327 -36
- data/lib/extlib/logger.rb +8 -8
- data/lib/extlib/mash.rb +45 -45
- data/lib/extlib/module.rb +1 -1
- data/lib/extlib/nil.rb +1 -1
- data/lib/extlib/numeric.rb +1 -1
- data/lib/extlib/object.rb +8 -21
- data/lib/extlib/object_space.rb +3 -3
- data/lib/extlib/pathname.rb +10 -0
- data/lib/extlib/pooling.rb +9 -17
- data/lib/extlib/rubygems.rb +7 -7
- data/lib/extlib/simple_set.rb +35 -8
- data/lib/extlib/string.rb +85 -42
- data/lib/extlib/struct.rb +10 -1
- data/lib/extlib/symbol.rb +11 -7
- data/lib/extlib/time.rb +31 -9
- data/lib/extlib/version.rb +1 -1
- data/lib/extlib/virtual_file.rb +1 -1
- data/spec/blank_spec.rb +85 -0
- data/spec/class_spec.rb +141 -0
- data/spec/datetime_spec.rb +22 -0
- data/spec/hash_spec.rb +537 -0
- data/spec/hook_spec.rb +1198 -0
- data/spec/inflection/plural_spec.rb +564 -0
- data/spec/inflection/singular_spec.rb +497 -0
- data/spec/inflection_extras_spec.rb +93 -0
- data/spec/lazy_array_spec.rb +1869 -0
- data/spec/mash_spec.rb +286 -0
- data/spec/module_spec.rb +58 -0
- data/spec/object_space_spec.rb +9 -0
- data/spec/object_spec.rb +114 -0
- data/spec/pooling_spec.rb +499 -0
- data/spec/simple_set_spec.rb +57 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/string_spec.rb +220 -0
- data/spec/struct_spec.rb +12 -0
- data/spec/symbol_spec.rb +8 -0
- data/spec/time_spec.rb +22 -0
- data/spec/try_dup_spec.rb +45 -0
- data/spec/virtual_file_spec.rb +21 -0
- metadata +51 -26
- data/README.txt +0 -3
data/lib/extlib/string.rb
CHANGED
@@ -2,32 +2,39 @@ require "pathname"
|
|
2
2
|
|
3
3
|
class String
|
4
4
|
##
|
5
|
-
#
|
5
|
+
# Escape all regexp special characters.
|
6
6
|
#
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# "*?{}.".escape_regexp #=> "\\*\\?\\{\\}\\."
|
8
|
+
#
|
9
|
+
# @return [String] Receiver with all regexp special characters escaped.
|
10
|
+
#
|
11
|
+
# @api public
|
9
12
|
def escape_regexp
|
10
13
|
Regexp.escape self
|
11
14
|
end
|
12
|
-
|
15
|
+
|
13
16
|
##
|
14
|
-
#
|
17
|
+
# Unescape all regexp special characters.
|
15
18
|
#
|
16
|
-
# @example
|
17
19
|
# "\\*\\?\\{\\}\\.".unescape_regexp #=> "*?{}."
|
20
|
+
#
|
21
|
+
# @return [String] Receiver with all regexp special characters unescaped.
|
22
|
+
#
|
23
|
+
# @api public
|
18
24
|
def unescape_regexp
|
19
25
|
self.gsub(/\\([\.\?\|\(\)\[\]\{\}\^\$\*\+\-])/, '\1')
|
20
26
|
end
|
21
|
-
|
27
|
+
|
22
28
|
##
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# "
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# @
|
30
|
-
#
|
29
|
+
# Convert to snake case.
|
30
|
+
#
|
31
|
+
# "FooBar".snake_case #=> "foo_bar"
|
32
|
+
# "HeadlineCNNNews".snake_case #=> "headline_cnn_news"
|
33
|
+
# "CNN".snake_case #=> "cnn"
|
34
|
+
#
|
35
|
+
# @return [String] Receiver converted to snake case.
|
36
|
+
#
|
37
|
+
# @api public
|
31
38
|
def snake_case
|
32
39
|
return self.downcase if self =~ /^[A-Z]+$/
|
33
40
|
self.gsub(/([A-Z]+)(?=[A-Z][a-z]?)|\B[A-Z]/, '_\&') =~ /_*(.*)/
|
@@ -35,57 +42,71 @@ class String
|
|
35
42
|
end
|
36
43
|
|
37
44
|
##
|
38
|
-
#
|
45
|
+
# Convert to camel case.
|
39
46
|
#
|
40
|
-
#
|
41
|
-
#
|
47
|
+
# "foo_bar".camel_case #=> "FooBar"
|
48
|
+
#
|
49
|
+
# @return [String] Receiver converted to camel case.
|
50
|
+
#
|
51
|
+
# @api public
|
42
52
|
def camel_case
|
43
53
|
return self if self !~ /_/ && self =~ /[A-Z]+.*/
|
44
54
|
split('_').map{|e| e.capitalize}.join
|
45
55
|
end
|
46
56
|
|
47
57
|
##
|
48
|
-
#
|
58
|
+
# Convert a path string to a constant name.
|
49
59
|
#
|
50
|
-
# @example
|
51
60
|
# "merb/core_ext/string".to_const_string #=> "Merb::CoreExt::String"
|
61
|
+
#
|
62
|
+
# @return [String] Receiver converted to a constant name.
|
63
|
+
#
|
64
|
+
# @api public
|
52
65
|
def to_const_string
|
53
66
|
gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
54
67
|
end
|
55
68
|
|
56
69
|
##
|
57
|
-
#
|
58
|
-
# The path that is associated with the constantized string, assuming a
|
59
|
-
# conventional structure.
|
70
|
+
# Convert a constant name to a path, assuming a conventional structure.
|
60
71
|
#
|
61
|
-
# @example
|
62
72
|
# "FooBar::Baz".to_const_path # => "foo_bar/baz"
|
73
|
+
#
|
74
|
+
# @return [String] Path to the file containing the constant named by receiver
|
75
|
+
# (constantized string), assuming a conventional structure.
|
76
|
+
#
|
77
|
+
# @api public
|
63
78
|
def to_const_path
|
64
79
|
snake_case.gsub(/::/, "/")
|
65
80
|
end
|
66
81
|
|
67
82
|
##
|
68
|
-
#
|
69
|
-
#
|
70
|
-
# @return <String> The original path concatenated with o.
|
83
|
+
# Join with _o_ as a file path.
|
71
84
|
#
|
72
|
-
# @example
|
73
85
|
# "merb"/"core_ext" #=> "merb/core_ext"
|
86
|
+
#
|
87
|
+
# @param [String] o Path component to join with receiver.
|
88
|
+
#
|
89
|
+
# @return [String] Receiver joined with o as a file path.
|
90
|
+
#
|
91
|
+
# @api public
|
74
92
|
def /(o)
|
75
93
|
File.join(self, o.to_s)
|
76
94
|
end
|
77
95
|
|
78
96
|
##
|
79
|
-
#
|
80
|
-
#
|
81
|
-
# @return <String> Relative path from between the two
|
97
|
+
# Calculate a relative path *from* _other_.
|
82
98
|
#
|
83
|
-
# @example
|
84
99
|
# "/opt/local/lib".relative_path_from("/opt/local/lib/ruby/site_ruby") # => "../.."
|
100
|
+
#
|
101
|
+
# @param [String] other Base path to calculate *from*.
|
102
|
+
#
|
103
|
+
# @return [String] Relative path from _other_ to receiver.
|
104
|
+
#
|
105
|
+
# @api public
|
85
106
|
def relative_path_from(other)
|
86
107
|
Pathname.new(self).relative_path_from(Pathname.new(other)).to_s
|
87
108
|
end
|
88
|
-
|
109
|
+
|
89
110
|
# Overwrite this method to provide your own translations.
|
90
111
|
def self.translate(value)
|
91
112
|
translations[value] || value
|
@@ -95,19 +116,33 @@ class String
|
|
95
116
|
@translations ||= {}
|
96
117
|
end
|
97
118
|
|
98
|
-
|
119
|
+
##
|
120
|
+
# Replace sequences of whitespace (including newlines) with either
|
121
|
+
# a single space or remove them entirely (according to param _spaced_)
|
99
122
|
#
|
100
|
-
# @example
|
101
123
|
# <<QUERY.compress_lines
|
102
124
|
# SELECT name
|
103
125
|
# FROM users
|
104
|
-
# QUERY
|
105
|
-
#
|
126
|
+
# QUERY => "SELECT name FROM users"
|
127
|
+
#
|
128
|
+
# @param [TrueClass, FalseClass] spaced (default=true)
|
129
|
+
# Determines whether returned string has whitespace collapsed or removed
|
130
|
+
#
|
131
|
+
# @return [String] Receiver with whitespace (including newlines) replaced
|
132
|
+
#
|
133
|
+
# @api public
|
106
134
|
def compress_lines(spaced = true)
|
107
135
|
split($/).map { |line| line.strip }.join(spaced ? ' ' : '')
|
108
136
|
end
|
109
137
|
|
110
|
-
|
138
|
+
##
|
139
|
+
# Remove whitespace margin.
|
140
|
+
#
|
141
|
+
# @param [Object] indicator ???
|
142
|
+
#
|
143
|
+
# @return [String] receiver with whitespace margin removed
|
144
|
+
#
|
145
|
+
# @api public
|
111
146
|
def margin(indicator = nil)
|
112
147
|
lines = self.dup.split($/)
|
113
148
|
|
@@ -120,12 +155,20 @@ class String
|
|
120
155
|
lines.map { |line| line.sub(/^\s{#{min_margin}}/, '') }.join($/)
|
121
156
|
end
|
122
157
|
|
123
|
-
|
158
|
+
##
|
159
|
+
# Formats String for easy translation. Replaces an arbitrary number of
|
124
160
|
# values using numeric identifier replacement.
|
125
161
|
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
162
|
+
# "%s %s %s" % %w(one two three) #=> "one two three"
|
163
|
+
# "%3$s %2$s %1$s" % %w(one two three) #=> "three two one"
|
164
|
+
#
|
165
|
+
# @param [#to_s] values
|
166
|
+
# A list of values to translate and interpolate into receiver
|
167
|
+
#
|
168
|
+
# @return [String]
|
169
|
+
# Receiver translated with values translated and interpolated positionally
|
170
|
+
#
|
171
|
+
# @api public
|
129
172
|
def t(*values)
|
130
173
|
self.class::translate(self) % values.collect! { |value| value.frozen? ? value : self.class::translate(value.to_s) }
|
131
174
|
end
|
data/lib/extlib/struct.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
class Struct
|
2
|
-
|
2
|
+
##
|
3
|
+
# Get a hash with names and values of all instance variables.
|
4
|
+
#
|
5
|
+
# class Foo < Struct.new(:name, :age, :gender); end
|
6
|
+
# f = Foo.new("Jill", 50, :female)
|
7
|
+
# f.attributes #=> {:name => "Jill", :age => 50, :gender => :female}
|
8
|
+
#
|
9
|
+
# @return [Hash] Hash of instance variables in receiver, keyed by ivar name
|
10
|
+
#
|
11
|
+
# @api public
|
3
12
|
def attributes
|
4
13
|
h = {}
|
5
14
|
each_pair { |k,v| h[k] = v }
|
data/lib/extlib/symbol.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
class Symbol
|
2
|
-
|
2
|
+
|
3
3
|
def try_dup
|
4
4
|
self
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
##
|
8
|
-
#
|
8
|
+
# Join with _o_ as a file path
|
9
9
|
#
|
10
|
-
#
|
10
|
+
# :merb/"core_ext" #=> "merb/core_ext"
|
11
|
+
# :merb / :core_ext / :string #=> "merb/core_ext/string"
|
11
12
|
#
|
12
|
-
# @
|
13
|
-
#
|
13
|
+
# @param [#to_s] o The path component(s) to append.
|
14
|
+
#
|
15
|
+
# @return [String] The receiver (as path string), concatenated with _o_.
|
16
|
+
#
|
17
|
+
# @api public
|
14
18
|
def /(o)
|
15
19
|
File.join(self.to_s, o.to_s)
|
16
20
|
end
|
17
|
-
end
|
21
|
+
end
|
data/lib/extlib/time.rb
CHANGED
@@ -1,19 +1,41 @@
|
|
1
|
+
require "date"
|
2
|
+
|
1
3
|
class Time
|
2
|
-
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
4
|
+
|
5
|
+
##
|
6
|
+
# Convert to ISO 8601 representation
|
7
|
+
#
|
8
|
+
# Time.now.to_json #=> "\"2008-03-28T17:54:20-05:00\""
|
9
|
+
#
|
10
|
+
# @return [String]
|
11
|
+
# ISO 8601 compatible representation of the Time object.
|
12
|
+
#
|
13
|
+
# @api public
|
8
14
|
def to_json(*)
|
9
15
|
self.xmlschema.to_json
|
10
16
|
end
|
11
|
-
|
17
|
+
|
18
|
+
##
|
19
|
+
# Return receiver (for DateTime/Time conversion protocol).
|
20
|
+
#
|
21
|
+
# Time.now.to_time #=> Wed Nov 19 20:08:28 -0800 2008
|
22
|
+
#
|
23
|
+
# @return [Time] Receiver
|
24
|
+
#
|
25
|
+
# @api public
|
12
26
|
def to_time
|
13
27
|
self
|
14
28
|
end
|
15
|
-
|
29
|
+
|
30
|
+
##
|
31
|
+
# Convert to DateTime (for DateTime/Time conversion protocol).
|
32
|
+
#
|
33
|
+
# Time.now.to_datetime #=> #<DateTime: 106046956823/43200,-1/3,2299161>
|
34
|
+
#
|
35
|
+
# @return [DateTime] DateTime object representing the same moment as receiver
|
36
|
+
#
|
37
|
+
# @api public
|
16
38
|
def to_datetime
|
17
39
|
DateTime.parse self.to_s
|
18
40
|
end
|
19
|
-
end
|
41
|
+
end
|
data/lib/extlib/version.rb
CHANGED
data/lib/extlib/virtual_file.rb
CHANGED
data/spec/blank_spec.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
describe Object do
|
4
|
+
it 'should provide blank?' do
|
5
|
+
Object.new.should respond_to(:blank?)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should be blank if it is nil' do
|
9
|
+
object = Object.new
|
10
|
+
class << object
|
11
|
+
def nil?; true end
|
12
|
+
end
|
13
|
+
object.should be_blank
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should be blank if it is empty' do
|
17
|
+
{}.should be_blank
|
18
|
+
[].should be_blank
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should not be blank if not nil or empty' do
|
22
|
+
Object.new.should_not be_blank
|
23
|
+
[nil].should_not be_blank
|
24
|
+
{ nil => 0 }.should_not be_blank
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe Numeric do
|
29
|
+
it 'should provide blank?' do
|
30
|
+
1.should respond_to(:blank?)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should never be blank' do
|
34
|
+
1.should_not be_blank
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe NilClass do
|
39
|
+
it 'should provide blank?' do
|
40
|
+
nil.should respond_to(:blank?)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should always be blank' do
|
44
|
+
nil.should be_blank
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe TrueClass do
|
49
|
+
it 'should provide blank?' do
|
50
|
+
true.should respond_to(:blank?)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should never be blank' do
|
54
|
+
true.should_not be_blank
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe FalseClass do
|
59
|
+
it 'should provide blank?' do
|
60
|
+
false.should respond_to(:blank?)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should always be blank' do
|
64
|
+
false.should be_blank
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe String do
|
69
|
+
it 'should provide blank?' do
|
70
|
+
'string'.should respond_to(:blank?)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should be blank if empty' do
|
74
|
+
''.should be_blank
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should be blank if it only contains whitespace' do
|
78
|
+
' '.should be_blank
|
79
|
+
" \r \n \t ".should be_blank
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should not be blank if it contains non-whitespace' do
|
83
|
+
' a '.should_not be_blank
|
84
|
+
end
|
85
|
+
end
|
data/spec/class_spec.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
class Grandparent
|
4
|
+
end
|
5
|
+
|
6
|
+
class Parent < Grandparent
|
7
|
+
end
|
8
|
+
|
9
|
+
class Child < Parent
|
10
|
+
end
|
11
|
+
|
12
|
+
class Parent
|
13
|
+
end
|
14
|
+
|
15
|
+
class Grandparent
|
16
|
+
class_inheritable_accessor :last_name, :_attribute
|
17
|
+
|
18
|
+
self._attribute = 1900
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Class, "#inheritable_accessor" do
|
22
|
+
|
23
|
+
after :each do
|
24
|
+
Grandparent.send(:remove_instance_variable, "@last_name") rescue nil
|
25
|
+
Parent.send(:remove_instance_variable, "@last_name") rescue nil
|
26
|
+
Child.send(:remove_instance_variable, "@last_name") rescue nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'inherits from parent unless overriden' do
|
30
|
+
Parent._attribute.should == 1900
|
31
|
+
Child._attribute.should == 1900
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'inherits from grandparent unless overriden' do
|
35
|
+
Child._attribute.should == 1900
|
36
|
+
end
|
37
|
+
|
38
|
+
it "inherits even if the accessor is made after the inheritance" do
|
39
|
+
Grandparent.last_name = "Merb"
|
40
|
+
Parent.last_name.should == "Merb"
|
41
|
+
Child.last_name.should == "Merb"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "supports ||= to change a child" do
|
45
|
+
Parent.last_name ||= "Merb"
|
46
|
+
Grandparent.last_name.should == nil
|
47
|
+
Parent.last_name.should == "Merb"
|
48
|
+
Child.last_name.should == "Merb"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "supports << to change a child when the parent is an Array" do
|
52
|
+
Grandparent.last_name = ["Merb"]
|
53
|
+
Parent.last_name << "Core"
|
54
|
+
Grandparent.last_name.should == ["Merb"]
|
55
|
+
Parent.last_name.should == ["Merb", "Core"]
|
56
|
+
end
|
57
|
+
|
58
|
+
it "supports ! methods on an Array" do
|
59
|
+
Grandparent.last_name = %w(Merb Core)
|
60
|
+
Parent.last_name.reverse!
|
61
|
+
Grandparent.last_name.should == %w(Merb Core)
|
62
|
+
Parent.last_name.should == %w(Core Merb)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "support modifying a parent Hash" do
|
66
|
+
Grandparent.last_name = {"Merb" => "name"}
|
67
|
+
Parent.last_name["Core"] = "name"
|
68
|
+
Parent.last_name.should == {"Merb" => "name", "Core" => "name"}
|
69
|
+
Grandparent.last_name.should == {"Merb" => "name"}
|
70
|
+
end
|
71
|
+
|
72
|
+
it "supports hard-merging a parent Hash" do
|
73
|
+
Grandparent.last_name = {"Merb" => "name"}
|
74
|
+
Parent.last_name.merge!("Core" => "name")
|
75
|
+
Parent.last_name.should == {"Merb" => "name", "Core" => "name"}
|
76
|
+
Grandparent.last_name.should == {"Merb" => "name"}
|
77
|
+
end
|
78
|
+
|
79
|
+
it "supports changes to the parent even if the child has already been read" do
|
80
|
+
Child.last_name
|
81
|
+
Grandparent.last_name = "Merb"
|
82
|
+
Child.last_name.should == "Merb"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "handles nil being set midstream" do
|
86
|
+
Child.last_name
|
87
|
+
Parent.last_name = nil
|
88
|
+
Grandparent.last_name = "Merb"
|
89
|
+
Child.last_name.should == nil
|
90
|
+
end
|
91
|
+
|
92
|
+
it "handles false being used in Parent" do
|
93
|
+
Child.last_name
|
94
|
+
Parent.last_name = false
|
95
|
+
Grandparent.last_name = "Merb"
|
96
|
+
Child.last_name.should == false
|
97
|
+
end
|
98
|
+
|
99
|
+
it "handles the grandparent changing the value (as long as the child isn't read first)" do
|
100
|
+
Grandparent.last_name = "Merb"
|
101
|
+
Grandparent.last_name = "Core"
|
102
|
+
Child.last_name.should == "Core"
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
# The bug that prompted this estoric spec was found in
|
109
|
+
# the wild when using dm-is-versioned with c_i_w.
|
110
|
+
#
|
111
|
+
|
112
|
+
module Plugin
|
113
|
+
def self.included(base)
|
114
|
+
base.class_eval do
|
115
|
+
class_inheritable_writer :plugin_options
|
116
|
+
class_inheritable_reader :plugin_options
|
117
|
+
self.plugin_options = :foo
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class Model
|
123
|
+
def self.new
|
124
|
+
model = Class.new
|
125
|
+
model.send(:include, Plugin)
|
126
|
+
model
|
127
|
+
end
|
128
|
+
|
129
|
+
include Plugin
|
130
|
+
self.const_set("Version", Model.new)
|
131
|
+
end
|
132
|
+
|
133
|
+
describe Class, "#inheritable_accessor" do
|
134
|
+
it "uses object_id for comparison" do
|
135
|
+
Model.methods.should include("plugin_options")
|
136
|
+
Model.plugin_options.should == :foo
|
137
|
+
|
138
|
+
Model::Version.methods.should include("plugin_options")
|
139
|
+
Model::Version.plugin_options.should == :foo
|
140
|
+
end
|
141
|
+
end
|