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,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