dm-core 1.1.0.rc2 → 1.1.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -8
- data/VERSION +1 -1
- data/dm-core.gemspec +24 -15
- data/lib/dm-core.rb +9 -48
- data/lib/dm-core/adapters.rb +1 -1
- data/lib/dm-core/adapters/abstract_adapter.rb +2 -1
- data/lib/dm-core/associations/many_to_many.rb +3 -3
- data/lib/dm-core/associations/many_to_one.rb +15 -4
- data/lib/dm-core/associations/one_to_many.rb +1 -1
- data/lib/dm-core/associations/relationship.rb +7 -6
- data/lib/dm-core/collection.rb +7 -2
- data/lib/dm-core/core_ext/pathname.rb +0 -14
- data/lib/dm-core/ext/array.rb +41 -0
- data/lib/dm-core/ext/blank.rb +24 -0
- data/lib/dm-core/ext/hash.rb +67 -0
- data/lib/dm-core/ext/module.rb +49 -0
- data/lib/dm-core/ext/object.rb +57 -0
- data/lib/dm-core/ext/singleton_class.rb +8 -0
- data/lib/dm-core/ext/string.rb +24 -0
- data/lib/dm-core/ext/try_dup.rb +12 -0
- data/lib/dm-core/model.rb +2 -1
- data/lib/dm-core/model/property.rb +3 -2
- data/lib/dm-core/property.rb +1 -1
- data/lib/dm-core/property/class.rb +1 -1
- data/lib/dm-core/property/date.rb +3 -3
- data/lib/dm-core/property/date_time.rb +3 -3
- data/lib/dm-core/property/time.rb +3 -3
- data/lib/dm-core/property/typecast/time.rb +2 -2
- data/lib/dm-core/property_set.rb +1 -1
- data/lib/dm-core/query.rb +9 -12
- data/lib/dm-core/resource.rb +2 -2
- data/lib/dm-core/spec/lib/counter_adapter.rb +1 -1
- data/lib/dm-core/spec/lib/spec_helper.rb +1 -1
- data/lib/dm-core/spec/shared/resource_spec.rb +2 -1
- data/lib/dm-core/support/equalizer.rb +1 -1
- data/lib/dm-core/support/hook.rb +0 -15
- data/lib/dm-core/support/inflections.rb +60 -0
- data/lib/dm-core/support/inflector.rb +3 -0
- data/lib/dm-core/support/inflector/inflections.rb +211 -0
- data/lib/dm-core/support/inflector/methods.rb +151 -0
- data/lib/dm-core/support/lazy_array.rb +4 -4
- data/lib/dm-core/support/mash.rb +176 -0
- data/lib/dm-core/support/subject.rb +1 -1
- data/lib/dm-core/version.rb +1 -1
- data/spec/public/model/relationship_spec.rb +2 -1
- data/spec/public/shared/collection_shared_spec.rb +5 -2
- data/spec/public/shared/finder_shared_spec.rb +10 -6
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +1 -1
- data/spec/semipublic/query_spec.rb +2 -2
- data/spec/semipublic/resource/state/immutable_spec.rb +2 -1
- data/spec/semipublic/resource/state_spec.rb +1 -3
- data/spec/semipublic/shared/resource_state_shared_spec.rb +2 -1
- data/spec/semipublic/shared/subject_shared_spec.rb +1 -1
- data/spec/support/core_ext/hash.rb +10 -0
- data/spec/support/core_ext/inheritable_attributes.rb +46 -0
- data/spec/unit/array_spec.rb +8 -20
- data/spec/unit/blank_spec.rb +62 -0
- data/spec/unit/data_mapper/ordered_set/hash_spec.rb +1 -1
- data/spec/unit/hash_spec.rb +8 -16
- data/spec/unit/lazy_array_spec.rb +3 -14
- data/spec/unit/mash_spec.rb +312 -0
- data/spec/unit/module_spec.rb +15 -15
- data/spec/unit/object_spec.rb +9 -9
- data/spec/unit/try_dup_spec.rb +8 -8
- metadata +32 -39
- data/lib/dm-core/core_ext/array.rb +0 -36
- data/lib/dm-core/core_ext/hash.rb +0 -30
- data/lib/dm-core/core_ext/module.rb +0 -46
- data/lib/dm-core/core_ext/object.rb +0 -31
- data/lib/dm-core/core_ext/string.rb +0 -22
- data/lib/dm-core/core_ext/try_dup.rb +0 -44
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'dm-core/
|
1
|
+
require 'dm-core/ext/try_dup'
|
2
2
|
|
3
3
|
class LazyArray # borrowed partially from StrokeDB
|
4
4
|
include Enumerable
|
@@ -358,9 +358,9 @@ class LazyArray # borrowed partially from StrokeDB
|
|
358
358
|
end
|
359
359
|
|
360
360
|
def initialize_copy(original)
|
361
|
-
@head = @head
|
362
|
-
@tail = @tail
|
363
|
-
@array = @array
|
361
|
+
@head = DataMapper::Ext.try_dup(@head)
|
362
|
+
@tail = DataMapper::Ext.try_dup(@tail)
|
363
|
+
@array = DataMapper::Ext.try_dup(@array)
|
364
364
|
end
|
365
365
|
|
366
366
|
def lazy_load
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module DataMapper
|
2
|
+
# This class has dubious semantics and we only have it so that people can write
|
3
|
+
# params[:key] instead of params['key'].
|
4
|
+
class Mash < Hash
|
5
|
+
|
6
|
+
# Initializes a new mash.
|
7
|
+
#
|
8
|
+
# @param [Hash, Object] constructor
|
9
|
+
# The default value for the mash. If +constructor+ is a Hash, a new mash
|
10
|
+
# will be created based on the keys of the hash and no default value will
|
11
|
+
# be set.
|
12
|
+
def initialize(constructor = {})
|
13
|
+
if constructor.is_a?(Hash)
|
14
|
+
super()
|
15
|
+
update(constructor)
|
16
|
+
else
|
17
|
+
super(constructor)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Gets the default value for the mash.
|
22
|
+
#
|
23
|
+
# @param [Object] key
|
24
|
+
# The default value for the mash. If +key+ is a Symbol and it is a key in
|
25
|
+
# the mash, then the default value will be set to the value matching the
|
26
|
+
# key.
|
27
|
+
def default(key = nil)
|
28
|
+
if key.is_a?(Symbol) && include?(key = key.to_s)
|
29
|
+
self[key]
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
36
|
+
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
37
|
+
|
38
|
+
# Sets the +value+ associated with the specified +key+.
|
39
|
+
#
|
40
|
+
# @param [Object] key The key to set.
|
41
|
+
# @param [Object] value The value to set the key to.
|
42
|
+
def []=(key, value)
|
43
|
+
regular_writer(convert_key(key), convert_value(value))
|
44
|
+
end
|
45
|
+
|
46
|
+
# Updates the mash with the key/value pairs from the specified hash.
|
47
|
+
#
|
48
|
+
# @param [Hash] other_hash
|
49
|
+
# A hash to update values in the mash with. The keys and the values will be
|
50
|
+
# converted to Mash format.
|
51
|
+
#
|
52
|
+
# @return [Mash] The updated mash.
|
53
|
+
def update(other_hash)
|
54
|
+
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
alias_method :merge!, :update
|
59
|
+
|
60
|
+
# Determines whether the mash contains the specified +key+.
|
61
|
+
#
|
62
|
+
# @param [Object] key The key to check for.
|
63
|
+
# @return [Boolean] True if the key exists in the mash.
|
64
|
+
def key?(key)
|
65
|
+
super(convert_key(key))
|
66
|
+
end
|
67
|
+
|
68
|
+
alias_method :include?, :key?
|
69
|
+
alias_method :has_key?, :key?
|
70
|
+
alias_method :member?, :key?
|
71
|
+
|
72
|
+
# @param [Object] key The key to fetch.
|
73
|
+
# @param [Array] *extras Default value.
|
74
|
+
#
|
75
|
+
# @return [Object] The value at key or the default value.
|
76
|
+
def fetch(key, *extras)
|
77
|
+
super(convert_key(key), *extras)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @param [Array] *indices
|
81
|
+
# The keys to retrieve values for.
|
82
|
+
#
|
83
|
+
# @return [Array] The values at each of the provided keys.
|
84
|
+
def values_at(*indices)
|
85
|
+
indices.collect {|key| self[convert_key(key)]}
|
86
|
+
end
|
87
|
+
|
88
|
+
# @param [Hash] hash The hash to merge with the mash.
|
89
|
+
#
|
90
|
+
# @return [Mash] A new mash with the hash values merged in.
|
91
|
+
def merge(hash)
|
92
|
+
self.dup.update(hash)
|
93
|
+
end
|
94
|
+
|
95
|
+
# @param [Object] key The key to delete from the mash.
|
96
|
+
def delete(key)
|
97
|
+
super(convert_key(key))
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns a mash that includes everything but the given +keys+.
|
101
|
+
#
|
102
|
+
# @param [Array<String, Symbol>] *keys The mash keys to exclude.
|
103
|
+
#
|
104
|
+
# @return [Mash] A new mash without the selected keys.
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# { :one => 1, :two => 2, :three => 3 }.except(:one)
|
108
|
+
# #=> { "two" => 2, "three" => 3 }
|
109
|
+
def except(*keys)
|
110
|
+
self.dup.except!(*keys.map {|k| convert_key(k)})
|
111
|
+
end
|
112
|
+
|
113
|
+
# Removes the specified +keys+ from the mash.
|
114
|
+
#
|
115
|
+
# @param [Array] *keys The mash keys to exclude.
|
116
|
+
#
|
117
|
+
# @return [Hash] +hash+
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# mash = { :one => 1, :two => 2, :three => 3 }
|
121
|
+
# mash.except!(:one, :two)
|
122
|
+
# mash # => { :three => 3 }
|
123
|
+
def except!(*keys)
|
124
|
+
keys.each { |key| delete(key) }
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
# Used to provide the same interface as Hash.
|
129
|
+
#
|
130
|
+
# @return [Mash] This mash unchanged.
|
131
|
+
def stringify_keys!; self end
|
132
|
+
|
133
|
+
# @return [Hash] The mash as a Hash with symbolized keys.
|
134
|
+
def symbolize_keys
|
135
|
+
h = Hash.new(default)
|
136
|
+
each { |key, val| h[key.to_sym] = val }
|
137
|
+
h
|
138
|
+
end
|
139
|
+
|
140
|
+
# @return [Hash] The mash as a Hash with string keys.
|
141
|
+
def to_hash
|
142
|
+
Hash.new(default).merge(self)
|
143
|
+
end
|
144
|
+
|
145
|
+
protected
|
146
|
+
# @param [Object] key The key to convert.
|
147
|
+
#
|
148
|
+
# @param [Object]
|
149
|
+
# The converted key. If the key was a symbol, it will be converted to a
|
150
|
+
# string.
|
151
|
+
#
|
152
|
+
# @api private
|
153
|
+
def convert_key(key)
|
154
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
155
|
+
end
|
156
|
+
|
157
|
+
# @param [Object] value The value to convert.
|
158
|
+
#
|
159
|
+
# @return [Object]
|
160
|
+
# The converted value. A Hash or an Array of hashes, will be converted to
|
161
|
+
# their Mash equivalents.
|
162
|
+
#
|
163
|
+
# @api private
|
164
|
+
def convert_value(value)
|
165
|
+
if value.class == Hash
|
166
|
+
mash = Mash.new(value)
|
167
|
+
mash.default = value.default
|
168
|
+
mash
|
169
|
+
elsif value.is_a?(Array)
|
170
|
+
value.collect { |e| convert_value(e) }
|
171
|
+
else
|
172
|
+
value
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
data/lib/dm-core/version.rb
CHANGED
@@ -281,7 +281,8 @@ share_examples_for 'it creates a many accessor' do
|
|
281
281
|
@expected.should_not be_nil
|
282
282
|
|
283
283
|
# set the model scope to only return the first record
|
284
|
-
@model.default_scope.update(
|
284
|
+
@model.default_scope.update(
|
285
|
+
DataMapper::Ext::Array.to_hash(@model.key(@repository.name).zip(@expected.key)))
|
285
286
|
|
286
287
|
@return = @car.model.get(*@car.key).__send__(@name)
|
287
288
|
end
|
@@ -123,7 +123,10 @@ share_examples_for 'A public Collection' do
|
|
123
123
|
end
|
124
124
|
|
125
125
|
it 'should update the Collection inline' do
|
126
|
-
@articles.each { |resource|
|
126
|
+
@articles.each { |resource|
|
127
|
+
DataMapper::Ext::Hash.only(resource.attributes, :title, :content).should ==
|
128
|
+
{ :title => 'Sample Article', :content => 'New Content' }
|
129
|
+
}
|
127
130
|
end
|
128
131
|
end
|
129
132
|
end
|
@@ -919,7 +922,7 @@ share_examples_for 'A public Collection' do
|
|
919
922
|
end
|
920
923
|
|
921
924
|
it 'should be a Resource with attributes matching the Hash' do
|
922
|
-
@return.first.attributes
|
925
|
+
DataMapper::Ext::Hash.only(@return.first.attributes, *@array.first.keys).should == @array.first
|
923
926
|
end
|
924
927
|
end
|
925
928
|
end
|
@@ -342,7 +342,8 @@ share_examples_for 'Finder Interface' do
|
|
342
342
|
|
343
343
|
describe 'with a collection' do
|
344
344
|
before :all do
|
345
|
-
@collection = @article_model.all(
|
345
|
+
@collection = @article_model.all(
|
346
|
+
DataMapper::Ext::Array.to_hash(@article_model.key.zip(@original.key)))
|
346
347
|
|
347
348
|
@return = @articles.all(:original => @collection)
|
348
349
|
end
|
@@ -479,7 +480,8 @@ share_examples_for 'Finder Interface' do
|
|
479
480
|
|
480
481
|
describe 'with a collection' do
|
481
482
|
before :all do
|
482
|
-
@collection = @article_model.all(
|
483
|
+
@collection = @article_model.all(
|
484
|
+
DataMapper::Ext::Array.to_hash(@article_model.key.zip(@new.key)))
|
483
485
|
|
484
486
|
@return = @articles.all(:previous => @collection)
|
485
487
|
end
|
@@ -615,7 +617,8 @@ share_examples_for 'Finder Interface' do
|
|
615
617
|
|
616
618
|
describe 'with a collection' do
|
617
619
|
before :all do
|
618
|
-
@collection = @article_model.all(
|
620
|
+
@collection = @article_model.all(
|
621
|
+
DataMapper::Ext::Array.to_hash(@article_model.key.zip(@new.key)))
|
619
622
|
|
620
623
|
@return = @articles.all(:revisions => @collection)
|
621
624
|
end
|
@@ -755,7 +758,8 @@ share_examples_for 'Finder Interface' do
|
|
755
758
|
|
756
759
|
describe 'with a collection' do
|
757
760
|
before :all do
|
758
|
-
@collection = @publication_model.all(
|
761
|
+
@collection = @publication_model.all(
|
762
|
+
DataMapper::Ext::Array.to_hash(@publication_model.key.zip(@publication.key)))
|
759
763
|
|
760
764
|
@return = @articles.all(:publications => @collection)
|
761
765
|
end
|
@@ -1093,7 +1097,7 @@ share_examples_for 'Finder Interface' do
|
|
1093
1097
|
end
|
1094
1098
|
|
1095
1099
|
it 'should be expected Resource' do
|
1096
|
-
@resource.attributes
|
1100
|
+
DataMapper::Ext::Hash.only(@resource.attributes, *@conditions.keys).should == @conditions
|
1097
1101
|
end
|
1098
1102
|
|
1099
1103
|
it 'should be a saved Resource' do
|
@@ -1136,7 +1140,7 @@ share_examples_for 'Finder Interface' do
|
|
1136
1140
|
end
|
1137
1141
|
|
1138
1142
|
it 'should be expected Resource' do
|
1139
|
-
@resource.attributes
|
1143
|
+
DataMapper::Ext::Hash.only(@resource.attributes, *@conditions.keys).should == @conditions
|
1140
1144
|
end
|
1141
1145
|
|
1142
1146
|
it 'should not be a saved Resource' do
|
@@ -791,7 +791,7 @@ describe DataMapper::Query do
|
|
791
791
|
it 'should raise an exception' do
|
792
792
|
lambda {
|
793
793
|
DataMapper::Query.new(@repository, @model, @options.update(:conditions => { 'unknown.id' => 1 }))
|
794
|
-
}.should raise_error(ArgumentError, "condition \"unknown.id\" does not map to a relationship in #{@model}")
|
794
|
+
}.should raise_error(ArgumentError, "condition \"unknown.id\" does not map to a property or relationship in #{@model}")
|
795
795
|
end
|
796
796
|
end
|
797
797
|
|
@@ -1952,7 +1952,7 @@ describe DataMapper::Query do
|
|
1952
1952
|
end
|
1953
1953
|
|
1954
1954
|
it 'should return expected value' do
|
1955
|
-
@return.should == <<-INSPECT
|
1955
|
+
@return.should == DataMapper::Ext::String.compress_lines(<<-INSPECT)
|
1956
1956
|
#<DataMapper::Query
|
1957
1957
|
@repository=:default
|
1958
1958
|
@model=User
|
@@ -21,7 +21,8 @@ describe DataMapper::Resource::State::Immutable do
|
|
21
21
|
@parent = @model.create(:name => 'John Doe')
|
22
22
|
|
23
23
|
@resource = @model.create(:name => 'Dan Kubb', :parent => @parent)
|
24
|
-
|
24
|
+
attributes = DataMapper::Ext::Array.to_hash(@model.key.zip(@resource.key))
|
25
|
+
@resource = @model.first(attributes.merge(:fields => [ :name, :parent_id ]))
|
25
26
|
|
26
27
|
@state = @resource.persisted_state
|
27
28
|
@state.should be_kind_of(DataMapper::Resource::State::Immutable)
|
@@ -181,9 +181,7 @@ describe DataMapper::Resource::State do
|
|
181
181
|
describe '#hash' do
|
182
182
|
subject { @state.hash }
|
183
183
|
|
184
|
-
it
|
185
|
-
should == @resource.hash
|
186
|
-
end
|
184
|
+
it { should == @state.class.hash ^ @resource.hash }
|
187
185
|
end
|
188
186
|
|
189
187
|
describe '#resource' do
|
@@ -49,7 +49,8 @@ share_examples_for 'Resource::State::Persisted#get' do
|
|
49
49
|
@resource.should be_dirty
|
50
50
|
@resource.save.should be(true)
|
51
51
|
|
52
|
-
|
52
|
+
attributes = DataMapper::Ext::Array.to_hash(@model.key.zip(@resource.key))
|
53
|
+
@resource = @model.first(attributes.merge(:fields => @model.key))
|
53
54
|
@state = @state.class.new(@resource)
|
54
55
|
|
55
56
|
# make sure the subject is not loaded
|
@@ -18,7 +18,7 @@ share_examples_for 'A semipublic Subject' do
|
|
18
18
|
subject { @subject_without_default.default_for(@resource) }
|
19
19
|
|
20
20
|
it 'should match the default value' do
|
21
|
-
should
|
21
|
+
DataMapper::Ext.blank?(subject).should == true
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'should be used as a default for the subject accessor' do
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Class
|
2
|
+
def class_inheritable_reader(*ivars)
|
3
|
+
instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
|
4
|
+
|
5
|
+
ivars.each do |ivar|
|
6
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
7
|
+
def self.#{ivar}
|
8
|
+
return @#{ivar} if defined?(@#{ivar})
|
9
|
+
return nil if self.object_id == #{self.object_id}
|
10
|
+
ivar = superclass.#{ivar}
|
11
|
+
return nil if ivar.nil?
|
12
|
+
@#{ivar} = DataMapper::Ext.try_dup(ivar)
|
13
|
+
end
|
14
|
+
RUBY
|
15
|
+
|
16
|
+
unless instance_reader == false
|
17
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
18
|
+
def #{ivar}
|
19
|
+
self.class.#{ivar}
|
20
|
+
end
|
21
|
+
RUBY
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def class_inheritable_writer(*ivars)
|
27
|
+
instance_writer = ivars.pop[:instance_writer] if ivars.last.is_a?(Hash)
|
28
|
+
ivars.each do |ivar|
|
29
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
30
|
+
def self.#{ivar}=(obj)
|
31
|
+
@#{ivar} = obj
|
32
|
+
end
|
33
|
+
RUBY
|
34
|
+
unless instance_writer == false
|
35
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
36
|
+
def #{ivar}=(obj) self.class.#{ivar} = obj end
|
37
|
+
RUBY
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def class_inheritable_accessor(*syms)
|
43
|
+
class_inheritable_reader(*syms)
|
44
|
+
class_inheritable_writer(*syms)
|
45
|
+
end
|
46
|
+
end
|
data/spec/unit/array_spec.rb
CHANGED
@@ -1,25 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'dm-core/
|
2
|
+
require 'dm-core/ext/array'
|
3
|
+
require 'dm-core/support/mash'
|
3
4
|
|
4
|
-
|
5
|
-
require 'active_support/hash_with_indifferent_access'
|
6
|
-
unless defined?(Mash)
|
7
|
-
Mash = ActiveSupport::HashWithIndifferentAccess
|
8
|
-
end
|
9
|
-
rescue LoadError
|
10
|
-
require 'extlib/mash'
|
11
|
-
end
|
12
|
-
|
13
|
-
describe Array do
|
5
|
+
describe DataMapper::Ext::Array do
|
14
6
|
before :all do
|
15
7
|
@array = [ [ :a, [ 1 ] ], [ :b, [ 2 ] ], [ :c, [ 3 ] ] ].freeze
|
16
8
|
end
|
17
9
|
|
18
|
-
|
19
|
-
|
20
|
-
describe '#to_hash' do
|
10
|
+
describe '.to_hash' do
|
21
11
|
before :all do
|
22
|
-
@return = @array
|
12
|
+
@return = DataMapper::Ext::Array.to_hash(@array)
|
23
13
|
end
|
24
14
|
|
25
15
|
it 'should return a Hash' do
|
@@ -31,15 +21,13 @@ describe Array do
|
|
31
21
|
end
|
32
22
|
end
|
33
23
|
|
34
|
-
|
35
|
-
|
36
|
-
describe '#to_mash' do
|
24
|
+
describe '.to_mash' do
|
37
25
|
before :all do
|
38
|
-
@return = @array
|
26
|
+
@return = DataMapper::Ext::Array.to_mash(@array)
|
39
27
|
end
|
40
28
|
|
41
29
|
it 'should return a Mash' do
|
42
|
-
@return.should be_kind_of(Mash)
|
30
|
+
@return.should be_kind_of(DataMapper::Mash)
|
43
31
|
end
|
44
32
|
|
45
33
|
it 'should return expected value' do
|