active_api 0.1.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.
@@ -0,0 +1,74 @@
1
+ module ActiveApi
2
+ class Definition
3
+ attr_reader :definition_name, :fields, :builder_class
4
+
5
+ def initialize(options)
6
+ @definition_name = options[:definition_name]
7
+ @builder_class = options[:builder_class] || ComplexType.to_s
8
+ @fields = options[:fields] || []
9
+ end
10
+
11
+ def attribute(name, type = :string, options = {})
12
+ field options.merge(:name => name, :type => type, :field_type => :attribute)
13
+ end
14
+
15
+ def element(name, type = :string, options = {})
16
+ send type, name, options
17
+ end
18
+
19
+ SimpleType.formats.each do |hash|
20
+ hash.each do |standard_name, xml_name|
21
+ define_method standard_name do |name, *options|
22
+ options = options.first || {}
23
+ field options.merge(:name => name, :type => standard_name, :klass => SimpleType)
24
+ end
25
+
26
+ if standard_name != xml_name
27
+ define_method xml_name do |name, *options|
28
+ options = options.first || {}
29
+ field options.merge(:name => name, :type => standard_name, :klass => SimpleType)
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def belongs_to(name, options = {})
36
+ field options.merge(:name => name, :type => :belongs_to, :klass => ComplexType)
37
+ end
38
+
39
+ def has_one(name, options = {})
40
+ field options.merge(:name => name, :type => :has_one, :klass => ComplexType)
41
+ end
42
+
43
+ def has_many(name, options = {})
44
+ field options.merge(:name => name, :type => :has_many, :klass => Collection)
45
+ end
46
+
47
+ def attributes
48
+ fields.select do |field|
49
+ field.field_type == :attribute
50
+ end
51
+ end
52
+
53
+ def elements
54
+ fields.select do |field|
55
+ field.field_type == :element
56
+ end
57
+ end
58
+
59
+ def singular_name
60
+ name.to_s.singularize
61
+ end
62
+
63
+ def plural_name
64
+ name.to_s.pluralize
65
+ end
66
+
67
+ private
68
+
69
+ def field(options)
70
+ self.fields << Field.new(options)
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,25 @@
1
+ module ActiveApi
2
+ class Field
3
+ attr_reader :type, :name, :klass, :value, :choice, :field_type
4
+
5
+ def initialize(options = {})
6
+ @type = options[:type]
7
+ @name = options[:name]
8
+ @klass = options[:klass]
9
+ @value = options[:value]
10
+ @choice = options[:choice]
11
+ @field_type = options[:field_type] || :element
12
+ end
13
+
14
+ def name_for(object)
15
+ if choice
16
+ value = object.send(name)
17
+ return nil if value.nil?
18
+ return choice[value.class.to_s]
19
+ else
20
+ name
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ module ActiveApi
2
+ module HasDefinition
3
+ def definition
4
+ schema.definitions.detect do |definition|
5
+ definition.definition_name == node.to_s.singularize.to_sym
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ module ActiveApi
2
+
3
+ class Schema
4
+ class_inheritable_array :versions
5
+
6
+ class << self
7
+ def version(version, options = {})
8
+ options[:definition_class] ||= Definition
9
+ schema = Schema.new version, options
10
+ yield schema
11
+ write_inheritable_array :versions, [schema]
12
+ schema
13
+ end
14
+
15
+ def find(version)
16
+ versions.detect { |schema| schema.version == version }
17
+ end
18
+ end
19
+
20
+ attr_reader :version, :definitions, :definition_class
21
+ def initialize(version, options = {})
22
+ @version = version
23
+ @definitions = []
24
+ @definition_class = options[:definition_class]
25
+ end
26
+
27
+ def define(name, options = {})
28
+ options[:definition_name] = name
29
+ definition = definition_class.to_s.constantize.new options
30
+ yield definition if block_given?
31
+ definitions << definition
32
+ end
33
+
34
+ def build_xml(objects, options)
35
+ Collection.new(objects, options.merge(:schema => self)).build_xml
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,103 @@
1
+ module ActiveApi
2
+ class SimpleType
3
+ include Builder
4
+
5
+ class << self
6
+ def formats
7
+ standard_names = [
8
+ :base64Binary,
9
+ :boolean,
10
+ :date,
11
+ :dateTime,
12
+ :dateTimeStamp,
13
+ :decimal,
14
+ :integer,
15
+ :long,
16
+ :int,
17
+ :short,
18
+ :byte,
19
+ :nonNegativeInteger,
20
+ :positiveInteger,
21
+ :unsignedLong,
22
+ :unsignedInt,
23
+ :unsignedShort,
24
+ :unsignedByte,
25
+ :nonPositiveInteger,
26
+ :negativeInteger,
27
+ :double,
28
+ :duration,
29
+ :dayTimeDuration,
30
+ :yearMonthDuration,
31
+ :float,
32
+ :gDay,
33
+ :gMonth,
34
+ :gMonthDay,
35
+ :gYear,
36
+ :gYearMonth,
37
+ :hexBinary,
38
+ :precisionDecimal,
39
+ :string,
40
+ :normalizedString,
41
+ :token,
42
+ :language,
43
+ :time
44
+ ].map do |format|
45
+ {format.to_s.underscore.to_sym => format}
46
+ end
47
+
48
+ custom_names = [
49
+ {:any_uri => :anyURI},
50
+ {:notation => :NOTATION},
51
+ {:qname => :QName},
52
+ {:name => :Name},
53
+ {:nc_name => :NCName},
54
+ {:entity => :ENTITY},
55
+ {:id => :ID},
56
+ {:idref => :IDREF},
57
+ {:nmtoken => :NMTOKEN},
58
+ ]
59
+
60
+ standard_names + custom_names
61
+ end
62
+
63
+ def default_format_proc
64
+ proc { |value| value }
65
+ end
66
+
67
+ def format_procs
68
+ {
69
+ :normalized_string => proc {|value| value },
70
+ :token => proc {|value| value },
71
+ :date_time => proc {|value| value.strftime("%Y-%m-%dT%H:%M:%S%Z") },
72
+ :time => proc {|value| value.strftime("%H:%M:%S%Z") },
73
+ :date => proc {|value| value.strftime("%Y-%m-%d") },
74
+ :any_uri => proc {|value| URI.escape(value) }
75
+ }
76
+ end
77
+ end
78
+
79
+ attr_reader :text, :node, :format
80
+
81
+ def initialize(text, options)
82
+ @text = text
83
+ @node = options[:node]
84
+ @format = options[:format]
85
+ end
86
+
87
+ def append(hash)
88
+ hash[node] = formatted_text
89
+ end
90
+
91
+ protected
92
+
93
+ def build(builder)
94
+ builder.send "#{node}_", formatted_text
95
+ end
96
+
97
+ def formatted_text
98
+ return nil if text.blank?
99
+ (self.class.format_procs[format] || self.class.default_format_proc).call(text)
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module ActiveApi
4
+ describe ComplexType do
5
+
6
+ before do
7
+ @article = Article.new
8
+ @article.id = 1
9
+ @article.title = "Some title"
10
+
11
+ @schema = Schema.version(:v1) do |xsl|
12
+ xsl.define :article do |t|
13
+ t.string :title
14
+ end
15
+ end
16
+ end
17
+
18
+ describe "with a definition with fields" do
19
+ it "emits the node and all fields within the node" do
20
+ element = ComplexType.new @article, :node => :article, :schema => @schema
21
+ doc = element.build_xml.doc
22
+ doc.xpath("/article/title").first.inner_text.should == @article.title
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module ActiveApi
4
+ describe Definition do
5
+
6
+ describe "#class_symbol" do
7
+ it "returns what is passed in" do
8
+ Definition.new(:definition_name => :article).definition_name.should == :article
9
+ end
10
+ end
11
+
12
+ describe "#fields" do
13
+ it "is empty by default" do
14
+ Definition.new(:definition_name => :article).fields.should be_empty
15
+ end
16
+ end
17
+
18
+ [:string, :has_many, :belongs_to, :has_one].each do |method_name|
19
+ describe "##{method_name}" do
20
+ it "adds a #{method_name} field with the options" do
21
+ definition = Definition.new(:definition_name => :article)
22
+ definition.send method_name, :title
23
+ definition.fields.length.should == 1
24
+ definition.fields.first.type.should == method_name
25
+ definition.fields.first.name.should == :title
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module ActiveApi
4
+ describe Field do
5
+ it "has a type" do
6
+ definition = Field.new :type => :string
7
+ definition.type.should == :string
8
+ end
9
+
10
+ it "has a name" do
11
+ definition = Field.new :name => :title
12
+ definition.name.should == :title
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module ActiveApi
4
+ describe Schema do
5
+
6
+ before do
7
+ Schema.version(:v1) do |schema|
8
+ schema.define :article do |t|
9
+ t.string :title
10
+ t.has_many :comments
11
+ end
12
+ end
13
+ end
14
+
15
+ describe ".define" do
16
+ describe "with a single field" do
17
+
18
+ it "adds one definition of the correct type" do
19
+ schema = Schema.find(:v1)
20
+ schema.definitions.length.should == 1
21
+ definition = schema.definitions.first
22
+ definition.should be_kind_of(Definition)
23
+ definition.definition_name.should == :article
24
+ end
25
+
26
+ it "sets the fields on the definition correctly" do
27
+ definition = Schema.find(:v1).definitions.first
28
+ definition.fields.length.should == 2
29
+ field = definition.fields.first
30
+ field.type.should == :string
31
+ field.name.should == :title
32
+ end
33
+ end
34
+
35
+ describe "with a multiple fields" do
36
+
37
+ it "adds one definition of the correct type article" do
38
+ schema = Schema.find(:v1)
39
+ schema.definitions.length.should == 1
40
+ definition = schema.definitions.first
41
+ definition.should be_kind_of(Definition)
42
+ definition.definition_name.should == :article
43
+ end
44
+
45
+ it "sets the fields on the definition correctly" do
46
+ definition = Schema.find(:v1).definitions.first
47
+ definition.fields.length.should == 2
48
+ field1 = definition.fields.first
49
+ field1.type.should == :string
50
+ field1.name.should == :title
51
+ field2 = definition.fields.last
52
+ field2.type.should == :has_many
53
+ field2.name.should == :comments
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module ActiveApi
4
+ describe SimpleType do
5
+
6
+ it "builds the node with the value" do
7
+ element = SimpleType.new "foo", :node => :bar
8
+ doc = element.build_xml.doc
9
+ doc.xpath("/bar").first.inner_text.should == "foo"
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,367 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module ActiveApi
4
+ describe "Defining a schema" do
5
+
6
+ describe "calling a collection from a schema" do
7
+ before do
8
+ @schema = Schema.version(:v1) do |xsl|
9
+ xsl.define :article do |t|
10
+ t.element :id, :string
11
+ end
12
+ end
13
+ @article = Article.new :id => 456
14
+ end
15
+
16
+ it "emits the string element" do
17
+ element = Schema.find(:v1).build_xml [@article], :node => :article
18
+ doc = element.doc
19
+ doc.xpath("/articles/article/id").inner_text.should == "456"
20
+ end
21
+ end
22
+
23
+ describe "with an element of type string" do
24
+ before do
25
+ @schema = Schema.version(:v1) do |xsl|
26
+ xsl.define :article do |t|
27
+ t.element :id, :string
28
+ end
29
+ end
30
+ @article = Article.new :id => 456
31
+ end
32
+
33
+ it "emits the string element" do
34
+ element = Collection.new [@article], :node => :article, :schema => @schema
35
+ doc = element.build_xml.doc
36
+ doc.xpath("/articles/article/id").inner_text.should == "456"
37
+ end
38
+ end
39
+
40
+ describe "with a string" do
41
+ before do
42
+ @schema = Schema.version(:v1) do |xsl|
43
+ xsl.define :article do |t|
44
+ t.string :title
45
+ end
46
+ end
47
+ @article = Article.new :title => Faker::Company.bs
48
+ end
49
+
50
+ it "emits the string element" do
51
+ element = Collection.new [@article], :node => :article, :schema => @schema
52
+ doc = element.build_xml.doc
53
+ doc.xpath("/articles/article/title").first.inner_text.should == @article.title
54
+ end
55
+ end
56
+
57
+ describe "with an attribute of type string" do
58
+ before do
59
+ @schema = Schema.version(:v1) do |xsl|
60
+ xsl.define :article do |t|
61
+ t.attribute :id
62
+ end
63
+ end
64
+ @article = Article.new :id => 456
65
+ end
66
+
67
+ it "emits the string attribute" do
68
+ element = Collection.new [@article], :node => :article, :schema => @schema
69
+ doc = element.build_xml.doc
70
+ doc.xpath("/articles/article[@id=456]").should be
71
+ end
72
+ end
73
+
74
+ describe "with other data types" do
75
+ before do
76
+ @article = Article.new :published_on => Date.parse("3/5/1956")
77
+ end
78
+
79
+ it "emits the correctly formatted element" do
80
+ @schema = Schema.version(:v1) do |xsl|
81
+ xsl.define :article do |t|
82
+ t.date :published_on
83
+ end
84
+ end
85
+ element = Collection.new [@article], :node => :article, :schema => @schema
86
+ doc = element.build_xml.doc
87
+ doc.xpath("/articles/article/published_on").first.inner_text.should == "1956-03-05"
88
+ end
89
+
90
+ it "emits nil when the value is nil" do
91
+ @schema = Schema.version(:v1) do |xsl|
92
+ xsl.define :article do |t|
93
+ t.date :published_on
94
+ end
95
+ end
96
+ @article.published_on = nil
97
+ element = Collection.new [@article], :node => :article, :schema => @schema
98
+ doc = element.build_xml.doc
99
+ doc.xpath("/articles/article/published_on").first.inner_text.should == ""
100
+ end
101
+
102
+ it "emits the correctly formatted attribute" do
103
+ @schema = Schema.version(:v1) do |xsl|
104
+ xsl.define :article do |t|
105
+ t.attribute :published_on, :type => :date
106
+ end
107
+ end
108
+ element = Collection.new [@article], :node => :article, :schema => @schema
109
+ doc = element.build_xml.doc
110
+ doc.xpath("/articles/article[@published_on=1956-03-05]").should be
111
+ end
112
+
113
+ it "emits nil when the attribute value is nil" do
114
+ @schema = Schema.version(:v1) do |xsl|
115
+ xsl.define :article do |t|
116
+ t.attribute :published_on, :type => :date
117
+ end
118
+ end
119
+ @article.published_on = nil
120
+ element = Collection.new [@article], :node => :article, :schema => @schema
121
+ doc = element.build_xml.doc
122
+ doc.xpath("/articles/article[@published_on='']").should be
123
+ end
124
+ end
125
+
126
+ describe "with a has_many element" do
127
+ before do
128
+ @schema = Schema.version(:v1) do |xsl|
129
+ xsl.define :article do |t|
130
+ t.has_many :comments
131
+ end
132
+ end
133
+
134
+ @article = Article.new :title => Faker::Company.bs
135
+ @comment = Comment.new :article => @article, :text => Faker::Company.bs
136
+ @article.comments = [@comment]
137
+ end
138
+
139
+ it "emits each of the child objects" do
140
+ @schema.define :comment do |t|
141
+ t.string :text
142
+ end
143
+
144
+ element = Collection.new [@article],
145
+ :node => :article,
146
+ :schema => @schema
147
+ doc = element.build_xml.doc
148
+ doc.xpath("/articles/article/comments/comment/text").first.inner_text.should == @comment.text
149
+ end
150
+ end
151
+
152
+ describe "with custom value procs" do
153
+ before do
154
+ @schema = Schema.version(:v1) do |xsl|
155
+ xsl.define :article do |t|
156
+ t.attribute :id, :value => proc {|attribute| "foo" }
157
+ t.string :id, :value => proc {|element| "foo" }
158
+ t.has_many :comments
159
+ end
160
+
161
+ xsl.define :comment do |t|
162
+ t.string :article_title, :value => proc{|element| element.object.article.title }
163
+ t.belongs_to :user
164
+ end
165
+
166
+ xsl.define :user do |t|
167
+ t.string :title, :value => proc{|element| element.parents[:article].title }
168
+ end
169
+ end
170
+
171
+ @article1 = Article.new :title => Faker::Company.bs
172
+ @article2 = Article.new :title => Faker::Lorem.sentence
173
+
174
+ @user = User.new
175
+ @comment1 = Comment.new :article => @article1, :user => @user
176
+ @comment2 = Comment.new :article => @article2, :user => @user
177
+
178
+ @article1.comments = [@comment1]
179
+ @article2.comments = [@comment2]
180
+ end
181
+
182
+ it "emits the value of the value proc for attributes" do
183
+ element = Collection.new [@article1],
184
+ :node => :article,
185
+ :schema => @schema
186
+ doc = element.build_xml.doc
187
+ doc.xpath("/articles/article[@id=foo]").should be
188
+ end
189
+
190
+ it "emits the value of the value proc for elements" do
191
+ element = Collection.new [@article1],
192
+ :node => :article,
193
+ :schema => @schema
194
+ doc = element.build_xml.doc
195
+ doc.xpath("/articles/article/id").first.inner_text.should == "foo"
196
+ end
197
+
198
+ it "emits the value of the value proc, which is passed an element containing a reference to the object" do
199
+ element = Collection.new [@article1],
200
+ :node => :article,
201
+ :schema => @schema
202
+ doc = element.build_xml.doc
203
+ doc.xpath("/articles/article/comments/comment/article_title").first.inner_text.should == @article1.title
204
+ end
205
+
206
+ it "emits the value of the value proc, which is passed an element containing a reference all ancestor objects" do
207
+ element = Collection.new [@article1, @article2],
208
+ :node => :article,
209
+ :schema => @schema
210
+ doc = element.build_xml.doc
211
+ doc.xpath("/articles/article").length.should == 2
212
+ doc.xpath("/articles/article/comments/comment/user/title").first.inner_text.should == @article1.title
213
+ doc.xpath("/articles/article/comments/comment/user/title").last.inner_text.should == @article2.title
214
+ end
215
+ end
216
+
217
+ describe "with belongs_to elements marked as choice" do
218
+ before do
219
+ @schema = Schema.version(:v1) do |xsl|
220
+ xsl.define :article do |t|
221
+ t.string :title
222
+ end
223
+
224
+ xsl.define :user do |t|
225
+ t.string :username
226
+ end
227
+
228
+ xsl.define :comment do |t|
229
+ t.belongs_to :commentable, :choice => {
230
+ "Article" => :article,
231
+ "User" => :user
232
+ }
233
+ end
234
+ end
235
+
236
+ @article = Article.new :title => Faker::Company.bs
237
+ @user = User.new :username => Faker::Internet.user_name
238
+ @comment1 = Comment.new :commentable => @article
239
+ @comment2 = Comment.new :commentable => @user
240
+ @comment3 = Comment.new :commentable => nil
241
+ end
242
+
243
+ it "uses the name of the class to lookup the definition to be used" do
244
+ element = Collection.new [@comment1, @comment2, @comment3], :node => :comment, :schema => @schema
245
+ doc = element.build_xml.doc
246
+ doc.xpath("/comments/comment").length.should == 3
247
+ doc.xpath("/comments/comment/article/title").inner_text.should == @article.title
248
+ doc.xpath("/comments/comment/user/username").inner_text.should == @user.username
249
+ doc.xpath("/comments/comment")[2].inner_text.should be_empty
250
+ end
251
+ end
252
+
253
+ describe "custom builders" do
254
+ before do
255
+ @schema = Schema.version(:v1) do |xsl|
256
+ xsl.define :article, :builder_class => "ActiveApi::MyCustomClass"
257
+ end
258
+
259
+ class MyCustomClass < ActiveApi::ComplexType
260
+ def build(builder)
261
+ builder.send :foo, :bar => "baz" do |xml|
262
+ xml.send :woot, "lol"
263
+ end
264
+ end
265
+ end
266
+
267
+ @article = Article.new :id => 456
268
+ end
269
+
270
+ it "uses the custom builder class" do
271
+ element = Schema.find(:v1).build_xml [@article], :node => :article
272
+ doc = element.doc
273
+ doc.xpath("/articles/foo[@bar='baz']/woot").first.inner_text.should == "lol"
274
+ end
275
+ end
276
+
277
+ describe "specifying a symbol as a value proc" do
278
+ before do
279
+ @schema = Schema.version(:v1) do |xsl|
280
+ xsl.define :article do |t|
281
+ t.string :foo, :value => :title
282
+ end
283
+ end
284
+
285
+ @article = Article.new :title => Faker::Company.bs
286
+ end
287
+
288
+ it "uses the custom builder class" do
289
+ element = Schema.find(:v1).build_xml [@article], :node => :article
290
+ doc = element.doc
291
+ doc.xpath("/articles/article/foo").first.inner_text.should == @article.title
292
+ end
293
+ end
294
+
295
+ describe "specifying a string literal as a value" do
296
+ before do
297
+ @schema = Schema.version(:v1) do |xsl|
298
+ xsl.define :article do |t|
299
+ t.string :foo, :value => "some value"
300
+ end
301
+ end
302
+
303
+ @article = Article.new :title => Faker::Company.bs
304
+ end
305
+
306
+ it "uses the custom builder class" do
307
+ element = Schema.find(:v1).build_xml [@article], :node => :article
308
+ doc = element.doc
309
+ doc.xpath("/articles/article/foo").first.inner_text.should == "some value"
310
+ end
311
+ end
312
+
313
+ describe "specifying custom definition classes with a string" do
314
+ before do
315
+ class MyDefinitionClass < Definition
316
+ def timestamps
317
+ date_time :created_at
318
+ date_time :updated_at
319
+ end
320
+ end
321
+
322
+ @schema = Schema.version(:v1, :definition_class => "ActiveApi::MyDefinitionClass") do |xsl|
323
+ xsl.define :article do |t|
324
+ t.timestamps
325
+ end
326
+ end
327
+
328
+ @article = Article.new :created_at => Date.parse("12/21/1945"), :updated_at => Date.parse("4/5/1992")
329
+ end
330
+
331
+ it "uses the custom builder class" do
332
+ element = Schema.find(:v1).build_xml [@article], :node => :article
333
+ doc = element.doc
334
+ doc.xpath("/articles/article/created_at").first.inner_text.should be_starts_with("1945-12-21")
335
+ doc.xpath("/articles/article/updated_at").first.inner_text.should be_starts_with("1992-04-05")
336
+ end
337
+ end
338
+
339
+ describe "specifying custom definition classes with a class" do
340
+ before do
341
+ class MyDefinitionClass < Definition
342
+ def timestamps
343
+ date_time :created_at
344
+ date_time :updated_at
345
+ end
346
+ end
347
+
348
+ @schema = Schema.version(:v1, :definition_class => MyDefinitionClass) do |xsl|
349
+ xsl.define :article do |t|
350
+ t.timestamps
351
+ end
352
+ end
353
+
354
+ @article = Article.new :created_at => Date.parse("12/21/1945"), :updated_at => Date.parse("4/5/1992")
355
+ end
356
+
357
+ it "uses the custom builder class" do
358
+ element = Schema.find(:v1).build_xml [@article], :node => :article
359
+ doc = element.doc
360
+ doc.xpath("/articles/article/created_at").first.inner_text.should be_starts_with("1945-12-21")
361
+ doc.xpath("/articles/article/updated_at").first.inner_text.should be_starts_with("1992-04-05")
362
+ end
363
+ end
364
+
365
+ end
366
+ end
367
+