icss 0.1.3 → 0.3.2

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 (98) hide show
  1. data/.watchr +35 -3
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile +19 -14
  4. data/README.md +296 -0
  5. data/Rakefile +2 -6
  6. data/TODO.md +13 -0
  7. data/VERSION +1 -1
  8. data/examples/avro_examples/complicated.icss.yaml +14 -13
  9. data/examples/bnc.icss.yaml +70 -0
  10. data/examples/chronic.icss.yaml +3 -3
  11. data/examples/license.icss.yaml +7 -0
  12. data/examples/source1.icss.yaml +4 -0
  13. data/examples/source2.icss.yaml +4 -0
  14. data/examples/test_icss.yaml +67 -0
  15. data/icss.gemspec +103 -43
  16. data/lib/icss.rb +37 -15
  17. data/lib/icss/core_types.rb +19 -0
  18. data/lib/icss/error.rb +4 -0
  19. data/{init.rb → lib/icss/init.rb} +0 -0
  20. data/lib/icss/message.rb +124 -66
  21. data/lib/icss/message/message_sample.rb +144 -0
  22. data/lib/icss/protocol.rb +184 -131
  23. data/lib/icss/protocol/code_asset.rb +18 -0
  24. data/lib/icss/protocol/data_asset.rb +23 -0
  25. data/lib/icss/protocol/license.rb +41 -0
  26. data/lib/icss/protocol/source.rb +37 -0
  27. data/lib/icss/protocol/target.rb +68 -0
  28. data/lib/icss/receiver_model.rb +24 -0
  29. data/lib/icss/receiver_model/active_model_shim.rb +36 -0
  30. data/lib/icss/receiver_model/acts_as_catalog.rb +170 -0
  31. data/lib/icss/receiver_model/acts_as_hash.rb +177 -0
  32. data/lib/icss/receiver_model/acts_as_loadable.rb +47 -0
  33. data/lib/icss/receiver_model/acts_as_tuple.rb +100 -0
  34. data/lib/icss/receiver_model/locale/en.yml +27 -0
  35. data/lib/icss/receiver_model/to_geo_json.rb +19 -0
  36. data/lib/icss/receiver_model/tree_merge.rb +34 -0
  37. data/lib/icss/receiver_model/validations.rb +31 -0
  38. data/lib/icss/serialization.rb +51 -0
  39. data/lib/icss/serialization/zaml.rb +443 -0
  40. data/lib/icss/type.rb +148 -501
  41. data/lib/icss/type/base_type.rb +0 -0
  42. data/lib/icss/type/named_type.rb +184 -0
  43. data/lib/icss/type/record_field.rb +77 -0
  44. data/lib/icss/type/record_model.rb +49 -0
  45. data/lib/icss/type/record_schema.rb +54 -0
  46. data/lib/icss/type/record_type.rb +325 -0
  47. data/lib/icss/type/simple_types.rb +72 -0
  48. data/lib/icss/type/structured_schema.rb +288 -0
  49. data/lib/icss/type/type_factory.rb +144 -0
  50. data/lib/icss/type/union_schema.rb +41 -0
  51. data/lib/icss/view_helper.rb +56 -19
  52. data/notes/named_array.md +32 -0
  53. data/notes/on_include_vs_extend_etc.rb +176 -0
  54. data/notes/technical_details.md +278 -0
  55. data/spec/core_types_spec.rb +119 -0
  56. data/spec/fixtures/zaml_complex_hash.yaml +35 -0
  57. data/spec/icss_spec.rb +86 -23
  58. data/spec/message/message_sample_spec.rb +4 -0
  59. data/spec/message_spec.rb +139 -0
  60. data/spec/protocol/license_spec.rb +67 -0
  61. data/spec/protocol/protocol_catalog_spec.rb +48 -0
  62. data/spec/protocol/protocol_validations_spec.rb +176 -0
  63. data/spec/protocol/source_spec.rb +65 -0
  64. data/spec/protocol_spec.rb +91 -37
  65. data/spec/receiver_model_spec.rb +111 -0
  66. data/spec/serialization/zaml_spec.rb +81 -0
  67. data/spec/serialization/zaml_test.rb +473 -0
  68. data/spec/serialization_spec.rb +63 -0
  69. data/spec/spec_helper.rb +24 -7
  70. data/spec/support/icss_test_helper.rb +67 -0
  71. data/spec/support/load_example_protocols.rb +17 -0
  72. data/spec/type/base_type_spec.rb +0 -0
  73. data/spec/type/named_type_spec.rb +75 -0
  74. data/spec/type/record_field_spec.rb +44 -0
  75. data/spec/type/record_model_spec.rb +206 -0
  76. data/spec/type/record_schema_spec.rb +161 -0
  77. data/spec/type/record_type_spec.rb +155 -0
  78. data/spec/type/simple_types_spec.rb +121 -0
  79. data/spec/type/structured_schema_spec.rb +300 -0
  80. data/spec/type/type_catalog_spec.rb +44 -0
  81. data/spec/type/type_factory_spec.rb +93 -0
  82. data/spec/type/union_schema_spec.rb +0 -0
  83. data/spec/type_spec.rb +63 -0
  84. metadata +205 -144
  85. data/CHANGELOG.textile +0 -9
  86. data/Gemfile.lock +0 -40
  87. data/README.textile +0 -29
  88. data/lib/icss/brevity.rb +0 -136
  89. data/lib/icss/code_asset.rb +0 -16
  90. data/lib/icss/core_ext.rb +0 -9
  91. data/lib/icss/data_asset.rb +0 -22
  92. data/lib/icss/old.rb +0 -96
  93. data/lib/icss/protocol_set.rb +0 -48
  94. data/lib/icss/sample_message_call.rb +0 -142
  95. data/lib/icss/target.rb +0 -72
  96. data/lib/icss/type/factory.rb +0 -196
  97. data/lib/icss/validations.rb +0 -16
  98. data/spec/validations_spec.rb +0 -171
@@ -0,0 +1,48 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'icss'
3
+
4
+ describe Icss::Meta::Protocol do
5
+ before do
6
+ Icss::Meta::Protocol.send :flush_registry
7
+ Icss::Meta::Protocol._catalog_loaded = true #prevent automatic loading of catalog
8
+ end
9
+ let(:protocol){ Icss::Meta::Protocol.receive(:protocol => 'test', :namespace => 'name.space') }
10
+
11
+ # Calling receive adds protocol to registry with after_receiver
12
+ describe :registry do
13
+ specify { Icss::Meta::Protocol.registry.should include('name.space.test' => protocol) }
14
+ end
15
+
16
+ describe '#find' do
17
+ context 'specific protocol name parameters' do
18
+ before { protocol } # load protocol into registry
19
+ it('return protocol'){ Icss::Meta::Protocol.find('name.space.test').should == protocol }
20
+ it('should error if not found'){ lambda{ Icss::Meta::Protocol.find('name.space.not.found') }.should raise_error(Icss::NotFoundError) }
21
+ it('should error for wildcard name'){ lambda{ Icss::Meta::Protocol.find('name.*.test') }.should raise_error(Icss::NotFoundError) }
22
+ end
23
+
24
+ context 'wildcard protocol name parameters' do
25
+ before { protocol } # load protocol into registry
26
+ context ':all' do
27
+ it('accepts wilcard names'){ Icss::Meta::Protocol.find(:all, 'name.*').should == [protocol] }
28
+ it('returns empty array if not found'){ Icss::Meta::Protocol.find(:all, 'not.*.found').should == [] }
29
+ end
30
+
31
+ context ':first' do
32
+ it('accepts wilcard names'){ Icss::Meta::Protocol.find(:first, 'name.*').should == protocol }
33
+ it('returns nil if not found'){ Icss::Meta::Protocol.find(:first, 'not.*.found').should be_nil }
34
+ end
35
+
36
+ context ':last' do
37
+ it('accepts wilcard names'){ Icss::Meta::Protocol.find(:last, 'name.*').should == protocol }
38
+ it('returns nil if not found'){ Icss::Meta::Protocol.find(:last, 'not.*.found').should be_nil }
39
+ end
40
+ end
41
+ end
42
+ describe '#all, #first, #last' do
43
+ before { protocol } # load protocol into registry
44
+ it('#all returns all protocols'){ Icss::Meta::Protocol.all.should == [protocol] }
45
+ it('#first returns first of all protocols'){ Icss::Meta::Protocol.first.should == protocol }
46
+ it('#last returns last of all protocols'){ Icss::Meta::Protocol.last.should == protocol }
47
+ end
48
+ end
@@ -0,0 +1,176 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'icss'
4
+
5
+ def template_icss
6
+ return <<EOS
7
+ ---
8
+ namespace: foo.bar
9
+ protocol: baz
10
+
11
+ data_assets:
12
+ - name: test_data_asset
13
+ location: data/test_data.tsv
14
+ type: test_data_record
15
+
16
+ messages:
17
+ search:
18
+ doc: A testable template message
19
+ request:
20
+ - name: test_request
21
+ type: test_request_record
22
+ response: test_data_record
23
+ samples:
24
+ - request:
25
+ - first_param: foo
26
+ second_param: bar
27
+
28
+ targets:
29
+ catalog:
30
+ - name: test_catalog_entry
31
+ title: Test Icss
32
+ description: This is a template Icss to test the error handling of the Icss library.
33
+ tags:
34
+ - test
35
+ - icss
36
+ - template
37
+ messages:
38
+ - search
39
+ packages:
40
+ - data_assets:
41
+ - test_data_asset
42
+
43
+ types:
44
+ - name: test_request_record
45
+ doc: A template request record
46
+ type: record
47
+ fields:
48
+ - name: first_param
49
+ doc: The first test parameter
50
+ type: string
51
+ - name: second param
52
+ doc: The second test parameter
53
+ type: string
54
+
55
+ - name: test_complex_data
56
+ doc: A template complex data type
57
+ type: record
58
+ fields:
59
+ - name: field_one
60
+ doc: A simple field for a complex data type
61
+ type: string
62
+ - name: field_two
63
+ doc: Another simple field for a complex data type
64
+ type: string
65
+
66
+ - name: test_data_record
67
+ doc: A template data record
68
+ type: record
69
+ fields:
70
+ - name: simple_data
71
+ doc: A simple piece of data
72
+ type: int
73
+ - name: complex_data
74
+ doc: A complex piece of data
75
+ type: test_complex_data
76
+
77
+ EOS
78
+ end
79
+
80
+ describe "Icss::Meta::Protocol validations" do
81
+ before :each do
82
+ @template = YAML.load(template_icss)
83
+ end
84
+
85
+ after :all do
86
+ Icss::Meta::TypeFactory.send :remove_instance_variable, :"@default_namespace"
87
+ end
88
+
89
+ it "should be able to receive a correctly formatted template Icss" do
90
+ lambda { @icss =Icss::Meta::Protocol.receive @template }.should_not raise_error
91
+ @icss.errors.should be_empty
92
+ end
93
+
94
+ it "should contain keys for all fields even if not included in the Icss file" do
95
+ @icss = Icss::Meta::Protocol.receive @template
96
+ @icss.keys.map{|k| k.to_s }.sort.should == (@template.keys | %w[code_assets _doc_hints _extra_params tags categories credits doc title]).sort
97
+ end
98
+
99
+ it "should generate an error when the namespace is formatted incorrectly" do
100
+ @template['namespace'] = '$bad_namespace'
101
+ Icss::Meta::Protocol.receive(@template).errors.keys.should == [:namespace]
102
+ end
103
+
104
+ it "should generate an error when the protocol is formatted incorrectly" do
105
+ @template['protocol'] = '$bad_protocol'
106
+ Icss::Meta::Protocol.receive(@template).errors.keys.should == [:protocol]
107
+ end
108
+
109
+ # context "Catalog Target" do
110
+ #
111
+ # it "should generate an error when an undefined data_asset is specified" do
112
+ # @template['targets']['catalog'].first['packages'].first['data_assets'] = ['fake_data_asset']
113
+ # Icss::Meta::Protocol.receive(@template).errors.keys.should == [:catalog]
114
+ # end
115
+ #
116
+ # it "should generate an error when an undefined message name is specified" do
117
+ # @template['targets']['catalog'].first['messages'] = ['fake_message']
118
+ # Icss::Meta::Protocol.receive(@template).errors.keys.should == [:catalog]
119
+ # end
120
+ #
121
+ # end
122
+ #
123
+ # context "Data Assets" do
124
+ #
125
+ # it "should generate an error when an asset's type is undefined" do
126
+ # @template['data_assets'].first['type'] = 'fake_data_asset'
127
+ # Icss::Meta::Protocol.receive(@template).errors.keys.should == [:data_assets]
128
+ # end
129
+ #
130
+ # end
131
+ #
132
+ # context "Messages" do
133
+ #
134
+ # it "should generate an error when a message's request type is undefined" do
135
+ # @template['messages']['search']['request'].first['type'] = 'fake_request_type'
136
+ # Icss::Meta::Protocol.receive(@template).errors.keys.should == [:messages]
137
+ # end
138
+ #
139
+ # it "should generate an error when a message's response type is undefined" do
140
+ # @template['messages']['search']['response'] = 'fake_response_type'
141
+ # Icss::Meta::Protocol.receive(@template).errors.keys.should == [:messages]
142
+ # end
143
+ #
144
+ # it "should generate an error when a message's sample request types do not match the request record" do
145
+ # @template['messages']['search']['samples'].first['request'] = [{ 'foo' => 'bar' }]
146
+ # Icss::Meta::Protocol.receive(@template).errors.keys.should == [:messages]
147
+ # end
148
+ #
149
+ # end
150
+
151
+ context "Types" do
152
+
153
+ it "should raise an error when an bad type definition is given for a specific type" do
154
+ @template['types'].push({
155
+ 'name' => 'fake_type_record',
156
+ 'type' => 'fake'
157
+ })
158
+ lambda{ Icss::Meta::Protocol.receive(@template) }.should raise_error(Icss::NotFoundError, /Cannot find.*fake/)
159
+ end
160
+
161
+ it "should generate an error when an undefined type definition is given for a specific field" do
162
+ @template['types'].push({
163
+ 'name' => 'fake_type_record',
164
+ 'type' => 'record',
165
+ 'fields' => [{
166
+ 'name' => 'fake_field',
167
+ 'type' => 'fake_type'
168
+ }]
169
+ })
170
+ lambda{ Icss::Meta::Protocol.receive(@template) }.should raise_error(Icss::NotFoundError, /Cannot find.*fake_type/)
171
+
172
+ end
173
+
174
+ end
175
+
176
+ end
@@ -0,0 +1,65 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'icss'
3
+
4
+ describe Icss::Meta::Source do
5
+ before do
6
+ Icss::Meta::Source.send :flush_registry
7
+ Icss::Meta::Source._catalog_loaded = true #prevent automatic loading of catalog
8
+ end
9
+ let(:source){ Icss::Meta::Source.receive(:source_id => 'sources.test', :title => 'Test source', :description => 'Source description', :url => 'http://test.com') }
10
+
11
+ describe '#name' do
12
+ specify { source.name.should == 'test' }
13
+ end
14
+
15
+ describe '#fullname' do
16
+ specify { source.fullname.should == 'sources.test' }
17
+ end
18
+
19
+
20
+
21
+ # Calling receive adds source to registry with after_receiver
22
+ describe :registry do
23
+ specify { Icss::Meta::Source.registry.should include('sources.test' => source) }
24
+ end
25
+
26
+ describe '#find' do
27
+ context 'specific source name parameters' do
28
+ before { source } # load source into registry
29
+ it('return source'){ Icss::Meta::Source.find('sources.test').should == source }
30
+ it('should error if not found'){ lambda{ Icss::Meta::Source.find('sources.not_found') }.should raise_error(Icss::NotFoundError) }
31
+ it('should error for wildcard name'){ lambda{ Icss::Meta::Source.find('sources.*.test') }.should raise_error(Icss::NotFoundError) }
32
+ end
33
+
34
+ context 'wildcard source name parameters' do
35
+ before { source } # load source into registry
36
+ context ':all' do
37
+ it('accepts wilcard names'){ Icss::Meta::Source.find(:all, 'sources.*').should == [source] }
38
+ it('returns empty array if not found'){ Icss::Meta::Source.find(:all, 'not.*.found').should == [] }
39
+ end
40
+
41
+ context ':first' do
42
+ it('accepts wilcard names'){ Icss::Meta::Source.find(:first, 'sources.*').should == source }
43
+ it('returns nil if not found'){ Icss::Meta::Source.find(:first, 'not.*.found').should be_nil }
44
+ end
45
+
46
+ context ':last' do
47
+ it('accepts wilcard names'){ Icss::Meta::Source.find(:last, 'sources.*').should == source }
48
+ it('returns nil if not found'){ Icss::Meta::Source.find(:last, 'not.*.found').should be_nil }
49
+ end
50
+ end
51
+ end
52
+ describe '#all, #first, #last' do
53
+ before { source } # load source into registry
54
+ it('#all returns all sources'){ Icss::Meta::Source.all.should == [source] }
55
+ it('#first returns first of all sources'){ Icss::Meta::Source.first.should == source }
56
+ it('#last returns last of all sources'){ Icss::Meta::Source.last.should == source }
57
+ end
58
+
59
+ describe '#to_hash' do
60
+ it { source.to_hash.should == {:source_id => 'sources.test',
61
+ :title => 'Test source',
62
+ :description => 'Source description',
63
+ :url => 'http://test.com'}}
64
+ end
65
+ end
@@ -1,26 +1,27 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'icss'
3
3
 
4
- describe Icss::Protocol do
4
+ describe Icss::Meta::Protocol do
5
+
5
6
  let(:simple_icss) do
6
- Icss::Protocol.receive_from_file(ICSS_ROOT_DIR('examples/chronic.icss.yaml'))
7
+ Icss::Meta::Protocol.receive_from_file(ENV.root_path('examples/chronic.icss.yaml'))
7
8
  end
8
9
 
9
10
  it 'loads cleanly' do
10
- simple_icss.name.should == 'chronic'
11
- simple_icss.fullname.should == 'util.time.chronic'
11
+ simple_icss.basename.should == 'chronic'
12
+ simple_icss.fullname.should == 'st.time_utils.chronic'
12
13
  end
13
14
 
14
15
  describe '#fullname' do
15
- it 'has namespace and name' do
16
- simple_icss.fullname.should == 'util.time.chronic'
16
+ it 'has namespace and basename' do
17
+ simple_icss.fullname.should == 'st.time_utils.chronic'
17
18
  simple_icss.namespace = nil
18
19
  simple_icss.fullname.should == 'chronic'
19
20
  end
20
21
  end
21
22
  describe '#path' do
22
23
  it 'is a / separated version of the name, with no / at start' do
23
- simple_icss.path.should == 'util/time/chronic'
24
+ simple_icss.path.should == 'st/time_utils/chronic'
24
25
  end
25
26
  end
26
27
  describe '#doc' do
@@ -31,7 +32,7 @@ describe Icss::Protocol do
31
32
 
32
33
  describe 'types' do
33
34
  it 'has an array of types' do
34
- simple_icss.types.map(&:name).should == ['chronic_parse_params', 'chronic_parse_response']
35
+ simple_icss.types.map(&:basename).should == ['chronic_parse_params', 'chronic_parse_response']
35
36
  end
36
37
  end
37
38
 
@@ -41,73 +42,126 @@ describe Icss::Protocol do
41
42
  end
42
43
 
43
44
  it 'named each message for its key' do
44
- simple_icss.messages['parse'].name.should == 'parse'
45
+ simple_icss.messages['parse'].basename.should == 'parse'
45
46
  simple_icss.receive!({ :messages => { 'foo' => { :request => [] } }})
46
- simple_icss.messages['foo'].name.should == 'foo'
47
+ simple_icss.messages['foo'].basename.should == 'foo'
47
48
  end
48
49
 
49
50
  it '#find_message' do
50
51
  msg = simple_icss.find_message(:parse)
51
- msg.should be_a(Icss::Message) ; msg.name.should == 'parse'
52
- msg = simple_icss.find_message('util.time.parse')
53
- msg.should be_a(Icss::Message) ; msg.name.should == 'parse'
54
- msg = simple_icss.find_message('util/time/parse')
55
- msg.should be_a(Icss::Message) ; msg.name.should == 'parse'
52
+ msg.should be_a(Icss::Meta::Message) ; msg.basename.should == 'parse'
53
+ msg = simple_icss.find_message('st.time_utils.parse')
54
+ msg.should be_a(Icss::Meta::Message) ; msg.basename.should == 'parse'
55
+ msg = simple_icss.find_message('st/time_utils/parse')
56
+ msg.should be_a(Icss::Meta::Message) ; msg.basename.should == 'parse'
56
57
  end
57
58
  end
58
59
 
59
60
  describe 'targets' do
60
61
  it 'has a hash of targets' do
61
- simple_icss.targets.keys.should == ['catalog']
62
- simple_icss.targets['catalog'].first.should be_a(Icss::CatalogTarget)
63
- simple_icss.targets['catalog'].first.name.should == 'util_time_chronic_parse'
62
+ simple_icss.targets.keys.should == [:catalog]
63
+ simple_icss.targets[:catalog].first.should be_a(Icss::CatalogTarget)
64
+ simple_icss.targets[:catalog].first.basename.should == 'st_time_utils_chronic_parse'
65
+ end
66
+ end
67
+
68
+ describe 'license' do
69
+ it 'returns nil if no license_id specified' do
70
+ simple_icss.license.should be_nil
71
+ end
72
+ it 'raises Icss::NotFoundError if license_id specified and not found' do
73
+ simple_icss.license_id = 'not_found_license'
74
+ lambda{ simple_icss.license }.should raise_error(Icss::NotFoundError, /Cannot find .*/)
75
+ end
76
+ it 'returns the Icss::Meta::License object' do
77
+ license = Icss::Meta::License.receive_from_file(ENV.root_path('examples/license.icss.yaml'))
78
+ simple_icss.license_id = 'licenses.example'
79
+ simple_icss.license.should == license
80
+ end
81
+ end
82
+
83
+
84
+
85
+ describe 'sources' do
86
+ it 'returns empty array if no source_ids specified' do
87
+ simple_icss.sources.should == {}
88
+ end
89
+ it 'raises Icss::NotFoundError if license_id specified and not found' do
90
+ simple_icss.credits = { :role => 'not_found_license' }
91
+ lambda{ simple_icss.sources }.should raise_error(Icss::NotFoundError, /Cannot find .*/)
92
+ end
93
+ it 'returns array of Icss::Meta::Source objects' do
94
+ source2 = Icss::Meta::Source.receive_from_file(ENV.root_path('examples/source2.icss.yaml'))
95
+ source1 = Icss::Meta::Source.receive_from_file(ENV.root_path('examples/source1.icss.yaml'))
96
+ simple_icss.credits = {:main => 'sources.source1', :uploaded => 'sources.source2'}
97
+ simple_icss.sources.should == { :main => source1, :uploaded => source2 }
64
98
  end
65
99
  end
66
-
67
- # describe 'tree_merge!' do
68
- # it 'merges recursively'
69
- # end
70
100
 
71
101
  describe 'validations' do
72
102
  it 'validates protocol name' do
73
103
  simple_icss.should be_valid
74
- simple_icss.protocol = '' ; simple_icss.should_not be_valid ; simple_icss.errors[:protocol].should == ["can't be blank"]
75
- simple_icss.protocol = '1bz' ; simple_icss.should_not be_valid ; simple_icss.errors[:protocol].should == ["must start with [A-Za-z_] and contain only [A-Za-z0-9_]."]
104
+ simple_icss.protocol = '' ; simple_icss.should_not be_valid ; simple_icss.errors[:protocol].should include("can't be blank")
105
+ simple_icss.protocol = '1bz' ; simple_icss.should_not be_valid ; simple_icss.errors[:protocol].should include("must start with [A-Za-z_] and contain only [A-Za-z0-9_].")
76
106
  end
77
107
 
78
108
  it 'validates namespace' do
79
109
  simple_icss.should be_valid
80
- simple_icss.namespace = '' ; simple_icss.should_not be_valid ; simple_icss.errors[:namespace].should == ["can't be blank"]
81
- simple_icss.namespace = '1bz' ; simple_icss.should_not be_valid ; simple_icss.errors[:namespace].first.should =~ /must be a dot-s/
110
+ simple_icss.namespace = '' ; simple_icss.should_not be_valid ; simple_icss.errors[:namespace].should include("can't be blank")
111
+ simple_icss.namespace = '1bz' ; simple_icss.should_not be_valid ; simple_icss.errors[:namespace].first.should =~ /Segments that start with.*joined by.*dots/
82
112
  end
83
113
  end
84
114
 
85
115
  describe '#to_hash' do
86
116
  it 'roundtrips' do
117
+ simple_icss.license_id = 'licenses.example'
118
+ simple_icss.credits = { :original => 'sources.source1' }
119
+ simple_icss.tags = ['tag1', 'tag2', 'tag3']
120
+ simple_icss.categories = ['category1', 'category2', 'category3']
87
121
  hsh = simple_icss.to_hash
88
122
  hsh.should == {
89
- :namespace=>"util.time", :protocol=>"chronic",
123
+ :namespace=>"st.time_utils", :protocol=>"chronic",
90
124
  :doc=>"A series of calls hooking into the Chronic ruby gem",
125
+ :license_id=>"licenses.example",
126
+ :credits=>{:original=>"sources.source1"},
127
+ :tags=>['tag1', 'tag2', 'tag3'],
128
+ :categories=>['category1', 'category2', 'category3'],
91
129
  :types => [
92
- {:name=>"chronic_parse_params", :doc=>"Query API parameters for the /util/time/chronic/parse call", :type=>:record,
130
+ {:name=>"st.time_utils.chronic_parse_params",
131
+ :namespace=>"st.time_utils",
132
+ :type=>:record,
133
+ :doc=>"Query API parameters for the /st/time_utils/chronic/parse call",
93
134
  :fields=>[
94
- {:name=>"time_str", :type=>:string, :doc=>"The string to parse."},
95
- {:name=>"context", :type=>:symbol, :doc=>"<tt>past</tt> or <tt>future</tt> (defaults to <tt>future</tt>)\nIf your string represents a birthday, you can set <tt>context</tt> to <tt>past</tt> and if an ambiguous string is given, it will assume it is in the past. Specify <tt>future</tt> or omit to set a future context."},
96
- {:name=>"now", :type=>:time, :doc=>"Time (defaults to Time.now)\nBy setting <tt>:now</tt> to a Time, all computations will be based off of that time instead of Time.now. If set to nil, Chronic will use the current time in UTC. You must supply a date that unambiguously parses with the much-less-generous ruby Time.parse()"},
97
- {:name=>"ambiguous_time_range", :type=>:int, :doc=>"Integer or <tt>:none</tt> (defaults to <tt>6</tt> (6am-6pm))\nIf an Integer is given, ambiguous times (like 5:00) will be assumed to be within the range of that time in the AM to that time in the PM. For example, if you set it to <tt>7</tt>, then the parser will look for the time between 7am and 7pm. In the case of 5:00, it would assume that means 5:00pm. If <tt>:none</tt> is given, no assumption will be made, and the first matching instance of that time will be used."}
135
+ {:name=>:time_str, :type=>:string, :doc=>"The string to parse."},
136
+ {:name=>:context, :type=>:symbol, :doc=>"<tt>past</tt> or <tt>future</tt> (defaults to <tt>future</tt>)\nIf your string represents a birthday, you can set <tt>context</tt> to <tt>past</tt> and if an ambiguous string is given, it will assume it is in the past. Specify <tt>future</tt> or omit to set a future context."},
137
+ {:name=>:now, :type=>:time, :doc=>"Time (defaults to Time.now)\nBy setting <tt>:now</tt> to a Time, all computations will be based off of that time instead of Time.now. If set to nil, Chronic will use the current time in UTC. You must supply a date that unambiguously parses with the much-less-generous ruby Time.parse()"},
138
+ {:name=>:ambiguous_time_range, :type=>:int, :doc=>"Integer or <tt>:none</tt> (defaults to <tt>6</tt> (6am-6pm))\nIf an Integer is given, ambiguous times (like 5:00) will be assumed to be within the range of that time in the AM to that time in the PM. For example, if you set it to <tt>7</tt>, then the parser will look for the time between 7am and 7pm. In the case of 5:00, it would assume that means 5:00pm. If <tt>:none</tt> is given, no assumption will be made, and the first matching instance of that time will be used."}
98
139
  ]},
99
- {:name=>"chronic_parse_response", :doc=>"Query API response for the /util/time/chronic/parse call", :type=>:record,
140
+ {:name=>"st.time_utils.chronic_parse_response",
141
+ :namespace=>"st.time_utils",
142
+ :type=>:record,
143
+ :doc=>"Query API response for the /util/time/chronic/parse call",
100
144
  :fields=>[
101
- {:name=>"time", :type=>:string, :doc=>"The UTC parsed time, as a \"ISO 8601 combined date time\":http://en.wikipedia.org/wiki/ISO_8601 string."},
102
- {:name=>"epoch_seconds", :type=>:int, :doc=>"The UTC parsed time, as \"epoch seconds\":http://en.wikipedia.org/wiki/Epoch_seconds integer."}
145
+ {:name=>:time, :type=>:string, :doc=>"The UTC parsed time, as a \"ISO 8601 combined date time\":http://en.wikipedia.org/wiki/ISO_8601 string."},
146
+ {:name=>:epoch_seconds, :type=>:int, :doc=>"The UTC parsed time, as \"epoch seconds\":http://en.wikipedia.org/wiki/Epoch_seconds integer."}
103
147
  ]}
104
148
  ],
105
149
  :messages => {
106
- 'parse' => {:doc=>"\nChronic is a natural language date/time parser written in pure Ruby. See below\nfor the wide variety of formats Chronic will parse.", :request=>[{:name=>"chronic_parse_params", :type=>"chronic_parse_params"}], :response=>"chronic_parse_response", :samples=>[{:request=>[{"time_str"=>"one hour ago", "now"=>"2007-03-16T12:09:08Z"}], :response=>{"epoch_seconds"=>1174043348, "time"=>"2007-03-16T11:09:08Z"}, :url=>"?now=2007-03-16T12%3A09%3A08Z&time_str=one%20hour%20ago"}, {:request=>[{"time_str"=>"Yesterday", "now"=>"5:06:07T2010-08-08Z"}], :response=>{"epoch_seconds"=>1281182400, "time"=>"2010-08-07T12:00:00Z"}, :url=>"?now=5%3A06%3A07%202010-08-08&time_str=Yesterday"}, {:url=>"?time_str=5pm+on+November+4th&context=past"}]},
150
+ :parse => {
151
+ :request =>[{:name=>:chronic_parse_params, :type=>"st.time_utils.chronic_parse_params"}],
152
+ :response =>"st.time_utils.chronic_parse_response",
153
+ :doc=>"\nChronic is a natural language date/time parser written in pure Ruby. See below\nfor the wide variety of formats Chronic will parse.",
154
+ :samples =>[{
155
+ :request=>[{"time_str"=>"one hour ago", "now"=>"2007-03-16T12:09:08Z"}],
156
+ :response=>{"epoch_seconds"=>1174043348, "time"=>"2007-03-16T11:09:08Z"}, :url=>"?now=2007-03-16T12%3A09%3A08Z&time_str=one%20hour%20ago"},
157
+ {:request=>[{"time_str"=>"Yesterday", "now"=>"5:06:07T2010-08-08Z"}],
158
+ :response=>{"epoch_seconds"=>1281182400, "time"=>"2010-08-07T12:00:00Z"}, :url=>"?now=5%3A06%3A07%202010-08-08&time_str=Yesterday"},
159
+ {:url=>"?time_str=5pm+on+November+4th&context=past"}]
160
+ },
107
161
  },
108
162
  :data_assets=>[],
109
163
  :code_assets=>[{:location=>"code/chronic_endpoint.rb"}],
110
- :targets => {"catalog"=>[{:name=>"util_time_chronic_parse", :title=>"Utils - Parse Times", :description=>"An API call to parse human-readable date / time strings", :tags=>["apiawesome", "ruby", "gems", "chronic", "time", "date", "util", "parse"], :messages=>["parse"]}]},
164
+ :targets => {:catalog=>[{:name=>"st_time_utils_chronic_parse", :title=>"Utils - Parse Times", :description=>"An API call to parse human-readable date / time strings", :tags=>["apiawesome", "ruby", "gems", "chronic", "time", "date", "util", "parse"], :messages=>["parse"]}]},
111
165
  }
112
166
  end
113
167
  end