icss 0.1.3 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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,119 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'yaml'
3
+ require 'icss'
4
+ require 'icss/protocol'
5
+ require 'icss/message'
6
+
7
+ def core_files
8
+ %w[ core datasets ].map do |section|
9
+ Dir[File.join(Settings[:catalog_root], section, '**/*.icss.yaml')].map do |fn|
10
+ fn.gsub(%r{.*(#{section}/[^\.]+)\.icss\.yaml$}, '\1')
11
+ end
12
+ # So that we can kinda have random load order, but have it be deterministic, sort by the reversed string
13
+ end.flatten.sort # _by(&:reverse)
14
+ end
15
+
16
+ unless defined?(Log)
17
+ if defined?(Rails)
18
+ Log = Rails.logger
19
+ else
20
+ require 'logger'
21
+ Log = Logger.new($stderr)
22
+ end
23
+ end
24
+
25
+ Log.level = 1
26
+
27
+ describe 'loads all catalog types' do
28
+ start_time = Time.now
29
+ last_time = Time.now
30
+ [
31
+ %w[ mu.rating prod.aggregate_rating mu.quantity mu.distance mu.duration
32
+ social.contact_point prod.item_availability prod.offer_item_condition
33
+ geo.geo_coordinates
34
+ culture.creative_work ev.event geo.place business.organization web.web_page_element
35
+ core/web/web_page
36
+ ].map{|s| "core/#{s}" },
37
+ 'datasets/science.astronomy.ufo_sighting',
38
+ core_files,
39
+ ].flatten.each do |filename_patt|
40
+ it "loads #{filename_patt}" do
41
+ Icss::Meta::Protocol.find(:all, filename_patt)
42
+ Log.debug "************* loaded #{Icss::Meta::Type.registry.size} core types in #{((Time.now-last_time).to_f * 1000).round} **************"
43
+ last_time = Time.now
44
+ end
45
+ end
46
+ end
47
+
48
+
49
+ #
50
+ # describe 'instances' do
51
+ # it '#new_record?'
52
+ # context 'partial response'
53
+ # context 'formatting'
54
+ # context 'reshaping' do
55
+ # it '#to_model'
56
+ # it '#to_param'
57
+ # it '#to_key' # Returns an Container of all key attributes if any is set, regardless if the object is persisted or not
58
+ # end
59
+ #
60
+ # end
61
+ #
62
+ # describe 'fields' do
63
+ # context '#name' do ; end
64
+ # context '#doc' do ; end
65
+ # context '#type' do ; end
66
+ # context '#default' do ; end
67
+ # context '#index'
68
+ # context '#versionating' do
69
+ # # acro versioning
70
+ # end
71
+ # context '#order' do
72
+ # it 'has sort_order'
73
+ # it 'order is an alias for sort_order'
74
+ # it 'is "ascending" by default'
75
+ # it 'sort_order_direction gives -1 / 0 / 1 for descending / ignore / ascending (default)'
76
+ # end
77
+ # context 'sugar' do
78
+ # it '#record?'
79
+ # it '#union?'
80
+ # it '#enum?'
81
+ # end
82
+ # it 'properties can find themselves in registry'
83
+ # it 'warns if you say "description" (should be "doc")'
84
+ # it 'warns if you say :items => FooFactory (should probably be :with if it is a Factory)'
85
+ #
86
+ # context '' do
87
+ # # universe, dimension, representation,
88
+ # # measurement_count, maximum_value, minimum_value, total_value, median_value, average_value, stdev_value
89
+ # end
90
+ # end
91
+ #
92
+ #
93
+ # describe 'hooks' do
94
+ # describe 'after_receive'
95
+ # # before/after initialize, validation, save, create, commit, rollback, destroy
96
+ # # #dirty?, #new_record?
97
+ # end
98
+ #
99
+ # # # not yet
100
+ # # describe 'associations' do
101
+ # # it '.belongs_to'
102
+ # # it '.has_one'
103
+ # # it '.has_many_through'
104
+ # # it '.has_many'
105
+ # # ASSOCIATION_METHODS = [:includes, :eager_load, :preload]
106
+ # # MULTI_VALUE_METHODS = [:select, :group, :order, :joins, :where, :having]
107
+ # # SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :create_with, :from]
108
+ # # end
109
+ #
110
+ #
111
+ # describe 'aspects' do
112
+ # end
113
+ #
114
+ # describe 'relationships' do
115
+ # end
116
+ #
117
+ # # describe Icss::Entity do
118
+ # #
119
+ # # end
@@ -0,0 +1,35 @@
1
+ ---
2
+ # first comment
3
+ complex: :hash
4
+ :items:
5
+ 2: !ruby/regexp /pairs/
6
+ Iñtërnâtiônàlizætiøn: look out for 'funny quotes'.
7
+ :and:
8
+ # informative comments
9
+ - :name: a few
10
+ :nested: elements
11
+ :including: |-
12
+ line
13
+ breaking
14
+ strings
15
+ :and_including: |
16
+ newline terminated
17
+ line
18
+ breaking
19
+ strings
20
+
21
+ :so: ":what\n :dyathink, :of, :that\n "
22
+ # more informative comments,
23
+ # spread across
24
+ # multiple lines
25
+ - :name: bob
26
+ # comment can be in hash key,
27
+ # spread across
28
+ # multiple lines;
29
+
30
+
31
+
32
+ - # does the right thing
33
+ # even when
34
+ # is the only item
35
+ []
@@ -1,27 +1,90 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'icss'
3
3
 
4
- describe Icss do
5
- describe "loading ICSS files from hackboxen and apeyeye" do
6
- [
7
- Dir[ICSS_ROOT_DIR('examples/hackboxen/**/*.icss.yaml')],
8
- Dir[ICSS_ROOT_DIR('examples/apeyeye_endpoints/**/*.icss.yaml')],
9
- ].flatten[0.. -1].each do |icss_filename|
10
- next if icss_filename =~ %r{culture/art}
11
-
12
- describe "#{icss_filename}" do
13
- before do
14
- @icss = Icss::Protocol.receive_from_file(icss_filename)
15
- end
16
-
17
- it "serializes out and in again" do
18
- #convert the icss to json and back
19
- raw_json = JSON.generate(@icss)
20
- json_icss = Icss::Protocol.receive(JSON.parse(raw_json))
21
-
22
- json_icss.to_hash.should == @icss.to_hash
23
- end
24
- end
25
- end
26
- end
4
+ def test_icss
5
+ YAML.load ENV.load_path('examples/infochimps-catalog/core/thing.icss.yaml')
27
6
  end
7
+
8
+ # describe Icss::Meta::Protocol do
9
+ #
10
+ #
11
+ # before :each do
12
+ # @icss = Icss::Meta::Protocol.receive test_icss
13
+ # end
14
+ #
15
+ # it "should be able to receive valid YAML files" do
16
+ # @icss.should be_a Icss::Meta::Protocol
17
+ # end
18
+ #
19
+ # # context "receiving referenced types" do
20
+ # #
21
+ # # it "should be able to identify the referenced type specified" do
22
+ # # ref_type = @icss.types.select{ |t| t.name == 'test_ref_type' }.first
23
+ # # ref_field = ref_type.field_schemas[:ref_field].first
24
+ # # ref_field.to_hash.should == {
25
+ # # :name => "ref_field",
26
+ # # :doc => "A field that references a type.",
27
+ # # :type => "place"
28
+ # # }
29
+ # # end
30
+ # #
31
+ # # it "should add the referenced type to the array of types for this protocol" do
32
+ # # puts Icss::Meta::DERIVED_TYPES.keys.inspect
33
+ # # @icss.types.map(&:name).should include 'place'
34
+ # # end
35
+ # #
36
+ # # end
37
+ #
38
+ # # context "receiving is_a" do
39
+ # #
40
+ # # it "should populate the fields array with the referenced type's fields"
41
+ # #
42
+ # # it "should allow additional field definitions to be added after the receive"
43
+ # #
44
+ # # it "should override referenced fields when a field is defined with the same name"
45
+ # #
46
+ # # end
47
+ # #
48
+ # # context "receiving identifier" do
49
+ # #
50
+ # # it "should be able to return all field definitions specified as identifiers"
51
+ # #
52
+ # # end
53
+ # #
54
+ # # context "receiving domain_id" do
55
+ # #
56
+ # # it "should be able to return the field definition specified as the domain_id"
57
+ # #
58
+ # # end
59
+ # #
60
+ # # context "receiving validates" do
61
+ # #
62
+ # # it "should be able validate the received values using the specified active model validators"
63
+ # #
64
+ # # end
65
+ # #
66
+ # # context "Icss::Klass" do
67
+ # #
68
+ # # it "should be able to return its values with dotted accessors"
69
+ # #
70
+ # # end
71
+ # #
72
+ # # context "transformation" do
73
+ # #
74
+ # # it " should be able to transform itself into a GeoJson object"
75
+ # #
76
+ # # context "receiving aspects" do
77
+ # #
78
+ # # it "should be able to generate a class form its apect's typing"
79
+ # #
80
+ # # it "should receive the aspect's properties first"
81
+ # #
82
+ # # it "should receive the original Icss::Klass properties"
83
+ # #
84
+ # # it "should receive the original Icss::Klass as an aspect, inlcuding left over properties"
85
+ # #
86
+ # # end
87
+ # #
88
+ # # end
89
+ #
90
+ # end
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'icss'
3
+ require ENV.root_path('spec/support/icss_test_helper')
4
+ include IcssTestHelper
@@ -0,0 +1,139 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'icss'
3
+ require ENV.root_path('spec/support/icss_test_helper')
4
+ include IcssTestHelper
5
+
6
+
7
+ describe Icss::Meta::Message do
8
+ before(:each) do
9
+ IcssTestHelper.remove_icss_constants('Poppa', 'Smurfette', 'Handy', 'Hefty')
10
+ class Icss::Poppa < Icss::SmurfRecord
11
+ field :smurfiness, Integer
12
+ end
13
+ class Icss::Smurfette < Icss::SmurfRecord
14
+ field :blondness, Integer
15
+ end
16
+ class Icss::Handy < Icss::Poppa
17
+ field :tool, Symbol, :default => :smurfwrench
18
+ field :weapon, Symbol, :default => :smurfthrower
19
+ end
20
+ end
21
+
22
+ let(:smurfy_message_hsh){
23
+ { :name => 'dance',
24
+ :doc => 'this is how we dance',
25
+ :request => [{ :name => 'params', :type => Icss::Poppa },],
26
+ :response => Icss::Smurfette,
27
+ :errors => ['oops']
28
+ } }
29
+ let(:smurfy_message){ Icss::Meta::Message.receive(smurfy_message_hsh) }
30
+
31
+ # ===========================================================================
32
+ #
33
+ # Message samples
34
+ #
35
+ describe Icss::Meta::MessageSample do
36
+ let(:samp_msg_hsh){
37
+ {
38
+ :name => 'lambada',
39
+ :request => [{ :smurfiness => 1, :blondness => 12 }],
40
+ :response_hsh => { :smurfiness => 1, :tool => :pipesmurf, :weapon => :broadsmurf },
41
+ }
42
+ }
43
+ let(:smurfy_message_sample){ Icss::Meta::MessageSample.receive(samp_msg_hsh) }
44
+
45
+ let(:message_with_sample){ Icss::Meta::Message.receive( smurfy_message_hsh.merge(:samples => [samp_msg_hsh])) }
46
+ it 'is created by its message' do
47
+ message_with_sample.should be_a(Icss::Meta::Message)
48
+ message_with_sample.samples.map(&:class).should == [Icss::Meta::MessageSample]
49
+ end
50
+ it 'knows its message' do
51
+ message_with_sample.samples.first.message.should == message_with_sample
52
+ end
53
+
54
+ describe 'basic behavior' do
55
+ subject{ smurfy_message_sample }
56
+ its('name'){ should == 'lambada' }
57
+ its('request'){ should == [{ :smurfiness => 1, :blondness => 12 }] }
58
+ its('response_hsh'){ should == { :smurfiness => 1, :tool => :pipesmurf, :weapon => :broadsmurf } }
59
+ end
60
+
61
+ # context 'loading from API' do
62
+ # it 'constructs a URL'
63
+ # it 'loads'
64
+ # it 'accepts a server'
65
+ # end
66
+
67
+ end
68
+
69
+ # ===========================================================================
70
+ #
71
+ # Message
72
+ #
73
+
74
+ describe 'basic behavior' do
75
+ subject{ smurfy_message }
76
+ its(:name){ should == 'dance' }
77
+ its('request.first.name'){ should == :params }
78
+ its('request.first.type'){ should == Icss::Poppa }
79
+ its(:params_type){ should == Icss::Poppa }
80
+ its(:response){ should == Icss::Smurfette }
81
+ its(:errors){ should == ['oops'] }
82
+ end
83
+
84
+ describe 'knows its protocol' do
85
+ let(:dance){ fun_protocol.messages[:dance] }
86
+
87
+ let(:fun_protocol_hsh){
88
+ { :protocol => 'smurf.village.fun',
89
+ :messages => { :dance => smurfy_message_hsh } } }
90
+ let(:fun_protocol){ Icss::Meta::Protocol.receive(fun_protocol_hsh) }
91
+ #
92
+ subject{ dance }
93
+ it{ should be_a(Icss::Meta::Message) }
94
+ it 'knows its protocol' do
95
+ dance.protocol.should == fun_protocol
96
+ end
97
+ its(:fullname){ should == 'smurf.village.fun.dance' }
98
+ its(:path){ should == 'smurf/village/fun/dance' }
99
+ end
100
+
101
+ describe '#to_hash' do
102
+ it 'correctly' do
103
+ smurfy_message.to_hash.should == {
104
+ :request => [{:name => :params, :type => "poppa"}],
105
+ :response => "smurfette",
106
+ :doc => "this is how we dance",
107
+ :errors => ["oops"],
108
+ :samples => []
109
+ }
110
+ end
111
+ end
112
+
113
+ describe 'reference tracking' do
114
+ {
115
+ 'simple type' => 'string',
116
+ 'named ref' => 'poppa',
117
+ 'class' => Icss::SmurfRecord,
118
+ }.each do |ref_type, ref|
119
+ it "is a reference if it receives a #{ref_type}" do
120
+ smurfy_message_hsh[:request].first[:type] = ref
121
+ msg = Icss::Meta::Message.receive(smurfy_message_hsh)
122
+ msg.request.map{|r| r.is_reference? }.should == [true]
123
+ end
124
+ end
125
+ {
126
+ 'record schema' => {:name => 'hefty', :type => :record, :fields => [:name => :strength, :type => :float]},
127
+ 'array schema' => {:type => :array, :items => :poppa},
128
+ 'hash schema' => {:type => :map, :values => :smurfette},
129
+ }.each do |ref_type, ref|
130
+ it "is not a reference if it receives a string" do
131
+ smurfy_message_hsh[:request].first[:type] = ref
132
+ msg = Icss::Meta::Message.receive(smurfy_message_hsh)
133
+ msg.request.map{|r| r.is_reference? }.should == [false]
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+ end
@@ -0,0 +1,67 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'icss'
3
+
4
+ describe Icss::Meta::License do
5
+ before do
6
+ Icss::Meta::License.send :flush_registry
7
+ Icss::Meta::License._catalog_loaded = true #prevent automatic loading of catalog
8
+ end
9
+ let(:license){ Icss::Meta::License.receive(:license_id => 'licenses.test', :title => 'Test license', :description => 'License description', :url => 'http://test.com', :summary => 'short summer of the license', :article_body => 'full text of license') }
10
+
11
+ describe '#name' do
12
+ specify { license.name.should == 'test' }
13
+ end
14
+
15
+ describe '#fullname' do
16
+ specify { license.fullname.should == 'licenses.test' }
17
+ end
18
+
19
+
20
+
21
+ # Calling receive adds license to registry with after_receiver
22
+ describe :registry do
23
+ specify { Icss::Meta::License.registry.should include('licenses.test' => license) }
24
+ end
25
+
26
+ describe '#find' do
27
+ context 'specific license name parameters' do
28
+ before { license } # load license into registry
29
+ it('return license'){ Icss::Meta::License.find('licenses.test').should == license }
30
+ it('should error if not found'){ lambda{ Icss::Meta::License.find('licenses.not_found') }.should raise_error(Icss::NotFoundError) }
31
+ it('should error for wildcard name'){ lambda{ Icss::Meta::License.find('licenses.*.test') }.should raise_error(Icss::NotFoundError) }
32
+ end
33
+
34
+ context 'wildcard license name parameters' do
35
+ before { license } # load license into registry
36
+ context ':all' do
37
+ it('accepts wilcard names'){ Icss::Meta::License.find(:all, 'licenses.*').should == [license] }
38
+ it('returns empty array if not found'){ Icss::Meta::License.find(:all, 'not.*.found').should == [] }
39
+ end
40
+
41
+ context ':first' do
42
+ it('accepts wilcard names'){ Icss::Meta::License.find(:first, 'licenses.*').should == license }
43
+ it('returns nil if not found'){ Icss::Meta::License.find(:first, 'not.*.found').should be_nil }
44
+ end
45
+
46
+ context ':last' do
47
+ it('accepts wilcard names'){ Icss::Meta::License.find(:last, 'licenses.*').should == license }
48
+ it('returns nil if not found'){ Icss::Meta::License.find(:last, 'not.*.found').should be_nil }
49
+ end
50
+ end
51
+ end
52
+ describe '#all, #first, #last' do
53
+ before { license } # load license into registry
54
+ it('#all returns all licenses'){ Icss::Meta::License.all.should == [license] }
55
+ it('#first returns first of all licenses'){ Icss::Meta::License.first.should == license }
56
+ it('#last returns last of all licenses'){ Icss::Meta::License.last.should == license }
57
+ end
58
+
59
+ describe '#to_hash' do
60
+ it { license.to_hash.should == {:license_id => 'licenses.test',
61
+ :title => 'Test license',
62
+ :description => 'License description',
63
+ :url => 'http://test.com',
64
+ :summary => 'short summer of the license',
65
+ :article_body => 'full text of license'}}
66
+ end
67
+ end