icss-activesupport-4 0.4.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.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.rspec +3 -0
  4. data/.watchr +52 -0
  5. data/CHANGELOG.md +38 -0
  6. data/Gemfile +22 -0
  7. data/LICENSE.textile +20 -0
  8. data/README.md +298 -0
  9. data/Rakefile +39 -0
  10. data/TODO.md +44 -0
  11. data/VERSION +1 -0
  12. data/examples/avro_examples/BulkData.avpr +21 -0
  13. data/examples/avro_examples/complicated.icss.yaml +159 -0
  14. data/examples/avro_examples/interop.avsc +32 -0
  15. data/examples/avro_examples/mail.avpr +20 -0
  16. data/examples/avro_examples/namespace.avpr +28 -0
  17. data/examples/avro_examples/org/apache/avro/ipc/HandshakeRequest.avsc +11 -0
  18. data/examples/avro_examples/org/apache/avro/ipc/HandshakeResponse.avsc +15 -0
  19. data/examples/avro_examples/org/apache/avro/ipc/trace/avroTrace.avdl +64 -0
  20. data/examples/avro_examples/org/apache/avro/ipc/trace/avroTrace.avpr +82 -0
  21. data/examples/avro_examples/org/apache/avro/mapred/tether/InputProtocol.avpr +59 -0
  22. data/examples/avro_examples/org/apache/avro/mapred/tether/OutputProtocol.avpr +75 -0
  23. data/examples/avro_examples/simple.avpr +70 -0
  24. data/examples/avro_examples/weather.avsc +9 -0
  25. data/examples/bnc.icss.yaml +70 -0
  26. data/examples/chronic.icss.yaml +115 -0
  27. data/examples/license.icss.yaml +7 -0
  28. data/examples/source1.icss.yaml +4 -0
  29. data/examples/source2.icss.yaml +4 -0
  30. data/examples/test_icss.yaml +67 -0
  31. data/icss.gemspec +168 -0
  32. data/icss_specification.textile +393 -0
  33. data/lib/icss.rb +53 -0
  34. data/lib/icss/core_types.rb +20 -0
  35. data/lib/icss/error.rb +4 -0
  36. data/lib/icss/init.rb +3 -0
  37. data/lib/icss/message.rb +133 -0
  38. data/lib/icss/message/message_sample.rb +144 -0
  39. data/lib/icss/protocol.rb +199 -0
  40. data/lib/icss/protocol/code_asset.rb +18 -0
  41. data/lib/icss/protocol/data_asset.rb +23 -0
  42. data/lib/icss/protocol/license.rb +41 -0
  43. data/lib/icss/protocol/source.rb +37 -0
  44. data/lib/icss/protocol/target.rb +68 -0
  45. data/lib/icss/receiver_model.rb +24 -0
  46. data/lib/icss/receiver_model/active_model_shim.rb +36 -0
  47. data/lib/icss/receiver_model/acts_as_catalog.rb +174 -0
  48. data/lib/icss/receiver_model/acts_as_hash.rb +177 -0
  49. data/lib/icss/receiver_model/acts_as_loadable.rb +47 -0
  50. data/lib/icss/receiver_model/acts_as_tuple.rb +100 -0
  51. data/lib/icss/receiver_model/locale/en.yml +27 -0
  52. data/lib/icss/receiver_model/to_geo_json.rb +19 -0
  53. data/lib/icss/receiver_model/tree_merge.rb +34 -0
  54. data/lib/icss/receiver_model/validations.rb +31 -0
  55. data/lib/icss/serialization.rb +51 -0
  56. data/lib/icss/serialization/zaml.rb +442 -0
  57. data/lib/icss/type.rb +168 -0
  58. data/lib/icss/type/base_type.rb +0 -0
  59. data/lib/icss/type/named_type.rb +185 -0
  60. data/lib/icss/type/record_field.rb +77 -0
  61. data/lib/icss/type/record_model.rb +49 -0
  62. data/lib/icss/type/record_schema.rb +54 -0
  63. data/lib/icss/type/record_type.rb +325 -0
  64. data/lib/icss/type/simple_types.rb +71 -0
  65. data/lib/icss/type/structured_schema.rb +288 -0
  66. data/lib/icss/type/type_factory.rb +144 -0
  67. data/lib/icss/type/union_schema.rb +41 -0
  68. data/lib/icss/view_helper.rb +65 -0
  69. data/notes/named_array.md +32 -0
  70. data/notes/on_include_vs_extend_etc.rb +176 -0
  71. data/notes/technical_details.md +278 -0
  72. data/spec/core_types_spec.rb +119 -0
  73. data/spec/fixtures/zaml_complex_hash.yaml +35 -0
  74. data/spec/icss_spec.rb +90 -0
  75. data/spec/message/message_sample_spec.rb +4 -0
  76. data/spec/message_spec.rb +139 -0
  77. data/spec/protocol/license_spec.rb +67 -0
  78. data/spec/protocol/protocol_catalog_spec.rb +48 -0
  79. data/spec/protocol/protocol_validations_spec.rb +176 -0
  80. data/spec/protocol/source_spec.rb +65 -0
  81. data/spec/protocol_spec.rb +170 -0
  82. data/spec/receiver_model_spec.rb +115 -0
  83. data/spec/serialization/zaml_spec.rb +82 -0
  84. data/spec/serialization/zaml_test.rb +473 -0
  85. data/spec/serialization_spec.rb +63 -0
  86. data/spec/spec_helper.rb +39 -0
  87. data/spec/support/icss_test_helper.rb +67 -0
  88. data/spec/support/load_example_protocols.rb +17 -0
  89. data/spec/type/base_type_spec.rb +0 -0
  90. data/spec/type/named_type_spec.rb +75 -0
  91. data/spec/type/record_field_spec.rb +44 -0
  92. data/spec/type/record_model_spec.rb +206 -0
  93. data/spec/type/record_schema_spec.rb +161 -0
  94. data/spec/type/record_type_spec.rb +155 -0
  95. data/spec/type/simple_types_spec.rb +121 -0
  96. data/spec/type/structured_schema_spec.rb +300 -0
  97. data/spec/type/type_catalog_spec.rb +44 -0
  98. data/spec/type/type_factory_spec.rb +93 -0
  99. data/spec/type/union_schema_spec.rb +0 -0
  100. data/spec/type_spec.rb +63 -0
  101. metadata +304 -0
data/lib/icss.rb ADDED
@@ -0,0 +1,53 @@
1
+ require 'gorillib/object/blank'
2
+ require 'gorillib/object/try_dup'
3
+ require 'gorillib/string/inflections'
4
+ require 'gorillib/string/constantize'
5
+ require 'gorillib/array/compact_blank'
6
+ require 'gorillib/array/extract_options'
7
+ require 'gorillib/hashlike'
8
+ require 'gorillib/hashlike/tree_merge'
9
+ require 'gorillib/hash/compact'
10
+ require 'gorillib/hash/keys'
11
+ require 'gorillib/hash/tree_merge'
12
+ require 'gorillib/metaprogramming/class_attribute'
13
+ require 'gorillib/serialization'
14
+ require 'gorillib/hashlike'
15
+
16
+ #
17
+ require 'configliere'
18
+ Settings.define :catalog_root, :type => :filename, :default => (defined?(Rails) ? (Rails.root+'catalog') : File.expand_path('../../ics/infochimps_catalog', __FILE__))
19
+ #
20
+ require 'icss/error'
21
+ require 'icss/receiver_model/acts_as_hash'
22
+ require 'icss/receiver_model/acts_as_loadable'
23
+ require 'icss/receiver_model/acts_as_catalog'
24
+ require 'icss/receiver_model/active_model_shim'
25
+ require 'icss/receiver_model/validations'
26
+ require 'icss/receiver_model/acts_as_tuple'
27
+ #
28
+ require 'icss/type' #
29
+ require 'icss/type/simple_types' # Boolean, Integer, ...
30
+ require 'icss/type/named_type' # class methods for a named type: .metamodel .doc, .fullname, &c
31
+ require 'icss/type/record_type' # class methods for a record model: .field, .receive,
32
+ require 'icss/type/record_model' # instance methods for a record model
33
+
34
+
35
+ #
36
+ require 'icss/type/type_factory' #
37
+ require 'icss/type/structured_schema' # generate type from array, hash, &c schema
38
+ require 'icss/type/union_schema' # factory for instances based on type
39
+ require 'icss/type/record_schema'
40
+ require 'icss/type/record_field'
41
+ #
42
+ require 'icss/receiver_model'
43
+ require 'icss/serialization'
44
+ #
45
+ require 'icss/message'
46
+ require 'icss/protocol/data_asset'
47
+ require 'icss/protocol/code_asset'
48
+ require 'icss/protocol/target'
49
+ require 'icss/protocol/license'
50
+ require 'icss/protocol/source'
51
+ require 'icss/protocol'
52
+ require 'icss/message/message_sample'
53
+
@@ -0,0 +1,20 @@
1
+ # p [__FILE__, "core types from ", Settings.catalog_root]
2
+
3
+ module Icss
4
+ module Encyclopedic ; module Wikipedia ; module Dbpedia ; end ; end ; end
5
+ module Web ; module An ; end ; end
6
+ module Web ; module Analytics ; end ; end
7
+ module Engineering ; module Chemical; module Msds ; end ; end ; end
8
+ module Government ; module Public ; module Acs ; end ; end ; end
9
+ module Language ; module Corpora ; module WordFreq ; end ; end ; end
10
+ module Sports ; module Stats ; module Baseball ; end ; module Vargatron ; end ; end ; end
11
+ module Social ; module Network ; module Tw ; end ; module Qwerly ; end ; end ; end
12
+ module Soc ; module Net ; module Tw ; end ; end ; end
13
+ module Meta ; module Req ; class Geolocator ; end ; end ; end
14
+ module St ; class Url < String ; end ; end
15
+ module Geo ; module Location ; end ; end
16
+ end
17
+
18
+ unless defined?(Icss::Geo::Place)
19
+ warn "Could not load core type 'place'. Make sure the catalog (#{Settings.catalog_root}) is where you expect it to be."
20
+ end
data/lib/icss/error.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Icss
2
+ class NotFoundError < ::NameError ; end unless defined?(NotFoundError)
3
+ class FactoryTypeMissing < ::ArgumentError ; end unless defined?(FactoryTypeMissing)
4
+ end
data/lib/icss/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'icss'
2
+ require 'icss/view_helper'
3
+
@@ -0,0 +1,133 @@
1
+ module Icss
2
+ module Meta
3
+ #
4
+ # Describes an Avro Message
5
+ #
6
+ # A message has attributes:
7
+ #
8
+ # * doc: an optional description of the message,
9
+ # * request: a list of named, typed parameter schemas (this has the same form as the fields of a record declaration);
10
+ # * response: a valid schema for the response
11
+ # * errors: an optional union of error schemas.
12
+ #
13
+ # A request parameter list is processed equivalently to an anonymous
14
+ # record. Since record field lists may vary between reader and writer, request
15
+ # parameters may also differ between the caller and responder, and such
16
+ # differences are resolved in the same manner as record field differences.
17
+ #
18
+ class Message
19
+ include ::Icss::ReceiverModel
20
+
21
+ field :name, String
22
+ alias_method :basename, :name
23
+ alias_method :basename=, :name=
24
+ field :doc, String
25
+
26
+ field :request_decorators, Hash, :default => {:anchors => []}
27
+
28
+ field :request, Array, :items => Icss::Meta::RecordField, :default => []
29
+ field :response, Icss::Meta::TypeFactory
30
+ field :errors, Object # FIXME: Icss::Meta::UnionType, :default => []
31
+ # this is defined in sample_message_call.rb -- since we don't do referenced types yet
32
+
33
+ attr_accessor :protocol
34
+
35
+ #we're starting to attach a lot of pork to this lib...
36
+ field :initial_free_qty, Integer
37
+ field :price_per_k_in_cents, Integer
38
+
39
+ after_receive(:are_my_types_references) do |hsh|
40
+ # track recursion of type references
41
+ @response_referenceness = ! hsh[:response].respond_to?(:each_pair)
42
+ end
43
+
44
+ after_receive(:parent_my_samples) do |hsh|
45
+ # # tie each sample back to this, its parent message
46
+ (self.samples||=[]).each{|samp| samp.message = self }
47
+ end
48
+
49
+ def fullname
50
+ "#{protocol.fullname}.#{basename}"
51
+ end
52
+ def path
53
+ fullname.gsub(%r{\.},'/')
54
+ end
55
+
56
+ # the type of the message's params (by convention, its first request field)
57
+ def params_type
58
+ request.first ? request.first.type : {}
59
+ end
60
+
61
+ def first_sample_request_param
62
+ req = samples.first.request.first rescue nil
63
+ req || {}
64
+ end
65
+
66
+ # ----------------------------------------
67
+ # GEO
68
+ #
69
+
70
+ def is_a_geo?
71
+ geolocators.present?
72
+ end
73
+
74
+ rcvr_alias(:is_geo, :is_geo)
75
+ def receive_is_geo(val)
76
+ return unless val
77
+ unless defined?(Icss::Meta::Req::Geolocator) then
78
+ warn "View helpers can\'t help with geolocators: Icss::Meta::Req::Geolocator type is missing. Is the catalog loaded properly?"
79
+ return
80
+ end
81
+ self.request_decorators = {
82
+ :anchors => [
83
+ Icss::Meta::Req::PointWithRadiusGeolocator,
84
+ Icss::Meta::Req::AddressTextGeolocator,
85
+ Icss::Meta::Req::TileXYZoomGeolocator,
86
+ Icss::Meta::Req::BoundingBoxGeolocator,
87
+ Icss::Meta::Req::IpAddressGeolocator
88
+ ],
89
+ }
90
+ end
91
+
92
+ def geolocators
93
+ request_decorators[:anchors]
94
+ end
95
+
96
+ #
97
+ # Conversion
98
+ #
99
+ def to_hash()
100
+ {
101
+ :request => summary_of_request_attr,
102
+ :response => summary_of_response_attr,
103
+ :doc => doc,
104
+ :errors => (errors.blank? ? nil : errors),
105
+ :samples => samples.map(&:to_hash).map(&:compact_blank),
106
+ :initial_free_qty => initial_free_qty,
107
+ :price_per_k_in_cents => price_per_k_in_cents,
108
+ }.compact
109
+ end
110
+ def to_json(*args) to_hash.to_json(*args) ; end
111
+
112
+ private
113
+ def summary_of_response_attr
114
+ case
115
+ when response.blank? then response
116
+ when @response_referenceness then response.fullname
117
+ else response.to_schema.compact_blank
118
+ end
119
+ end
120
+ def summary_of_request_attr
121
+ request.map do |req|
122
+ case
123
+ when req.blank? then req
124
+ # Is there a case where this needs to be a string and not a hash?
125
+ # when req.is_reference? then req.type.fullname
126
+ else req.to_schema.compact_blank
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ end
@@ -0,0 +1,144 @@
1
+ module Icss
2
+ module Meta
3
+ #
4
+ # Holds a sample call for a message and its expected response
5
+ #
6
+ # You may define the request parameters using an array of parameters
7
+ # or with the corresponding URL it would render to.
8
+ #
9
+ # This file also decorates Icss::Meta::Message and Icss::Meta::Protocol with helper methods for sample calls.
10
+ #
11
+ class MessageSample
12
+ include ReceiverModel
13
+ field :name, String
14
+ field :doc, String
15
+ field :request, Array, :default => []
16
+ field :response_hsh, Hash # a hash suitable for populating the message's @response@ type
17
+ field :response, Hash
18
+ attr_accessor :raw_response # the raw http response from fetching
19
+ field :error, String
20
+ field :url, String
21
+ attr_accessor :message
22
+
23
+ # Whips up the class implied by the ICSS type of this message's response,
24
+ # and populates it using the response hash.
25
+ def response_obj
26
+ return if response.blank?
27
+ message.response.receive(response)
28
+ end
29
+
30
+ # The URL implied by the given hostname and the sample request parameters.
31
+ #
32
+ # @param [String] hostname The hostname or hostname:port to include in the URL
33
+ # @param [Hash] extra_query_params A hash of extra params to in
34
+ #
35
+ # The URI expects string values in the hash used to build the query -- if
36
+ # calling #to_s on a field won't do what you want, clobber the value beforehand.
37
+ #
38
+ def full_url hostname, extra_query_params={}
39
+ host, port = hostname.split(':', 2)
40
+ u = Addressable::URI.new(:host => host, :port => port, :path => self.path, :scheme => 'http')
41
+ u.query_values = query_hash(extra_query_params)
42
+ u
43
+ end
44
+
45
+ def query_hash extra_query_params={}
46
+ hsh = (@url.present? ? @url.query_values : request.first.to_hash) rescue {}
47
+ hsh = hsh.merge extra_query_params
48
+ hsh.each{|k,v| hsh[k] = v.to_s }
49
+ hsh
50
+ end
51
+
52
+ def path
53
+ ((@url && @url.path).present? ? @url.path : "/#{message.path}" )
54
+ end
55
+
56
+ # @param [String, Addressable::URI]
57
+ # the URL can be fully-qualified (htttp://api.infochimps.com/this/that?the=other) or relative (this/that?the=other)
58
+ # and the path must match that of the message.
59
+ #
60
+ def url= new_url
61
+ if new_url.is_a?(String)
62
+ unless new_url.include?('?') then warn "sample request url should have a '?' introducing its query parameters: {#{new_url}}" ; end
63
+ new_url = Addressable::URI.parse(new_url)
64
+ end
65
+ @url = new_url
66
+ end
67
+
68
+ # retrieve the response from the given host, storing it in response. this
69
+ # catches all server errors and constructs a dummy response hash if the call
70
+ # fails.
71
+ def fetch_response! hostname="", extra_query_params={}
72
+ self.raw_response = fetch_raw_response( full_url(hostname, extra_query_params) )
73
+ begin
74
+ resp_hsh = JSON.load(raw_response.body)
75
+ rescue StandardError => e
76
+ warn [" error parsing response: #{e}"].join("\n")
77
+ self.response = nil
78
+ self.error = "JsonParseError"
79
+ return
80
+ end
81
+ if raw_response.code == 200
82
+ self.response = resp_hsh
83
+ self.error = nil
84
+ else
85
+ self.response = nil
86
+ self.error = resp_hsh["error"]
87
+ end
88
+ end
89
+
90
+ protected
91
+
92
+ def fetch_raw_response full_url
93
+ RestClient.get(full_url.to_s) do |response, request, result|
94
+ response
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ end
101
+
102
+ class Icss::Meta::Message
103
+ field :samples, Array, :items => Icss::Meta::MessageSample, :default => []
104
+ end
105
+
106
+ class Icss::Meta::Protocol
107
+
108
+ #
109
+ # a hash for dumping to file:
110
+ # @example: from the whole thing, would dump only this:
111
+ #
112
+ # namespace: util.time
113
+ # protocol: chronic
114
+ # messages:
115
+ # parse:
116
+ # samples:
117
+ # - url: "?now=5%3A06%3A07%202010-08-08&time_str=Yesterday"
118
+ # response: { "time": "2010-08-07 05:06:07 UTC", "epoch_seconds": 1281225967 }
119
+ #
120
+ def message_samples_hash
121
+ hsh = { :namespace => namespace, :protocol => protocol, :messages => {} }
122
+ messages.each do |msg_name, msg|
123
+ hsh[:messages][msg_name] = { :samples => [] }
124
+ msg.samples.each do |sample_req|
125
+ sample_hsh = {
126
+ :name => sample_req.name,
127
+ :doc => sample_req.doc,
128
+ }
129
+ if sample_req.response.present?
130
+ then sample_hsh[:response] = sample_req.response
131
+ else sample_hsh[:error] = sample_req.error
132
+ end
133
+ if sample_req.url.present?
134
+ then sample_hsh[:url] = sample_req.url.to_s
135
+ else sample_hsh[:request] = sample_req.request
136
+ end
137
+ sample_hsh.compact_blank!
138
+ hsh[:messages][msg_name][:samples] << sample_hsh
139
+ end
140
+ end
141
+ return hsh
142
+ end
143
+
144
+ end
@@ -0,0 +1,199 @@
1
+ module Icss
2
+ module Meta
3
+
4
+ # predefine so we can use below
5
+
6
+ class Message ; end
7
+
8
+ #
9
+ # Describes an Avro Protocol Declaration
10
+ #
11
+ # Avro protocols describe RPC interfaces. The Protocol class will receive an
12
+ # Avro JSON
13
+ #
14
+ # A Protocol has the following attributes:
15
+ #
16
+ # * protocol, a string, the name of the protocol (required). +name+ is
17
+ # provided as an alias for +protocol+.
18
+ #
19
+ # * namespace, a string that qualifies the name (optional).
20
+ #
21
+ # * doc, a string describing this protocol (optional).
22
+ #
23
+ # * types, an optional list of definitions of named types (records, enums,
24
+ # fixed and errors). An error definition is just like a record definition
25
+ # except it uses "error" instead of "record". Note that forward references
26
+ # to named types are not permitted.
27
+ #
28
+ # * messages, an optional JSON object whose keys are message names and whose
29
+ # values are objects whose attributes are described below. No two messages
30
+ # may have the same name.
31
+ #
32
+ # The name and namespace qualification rules defined for schema objects apply
33
+ # to protocols as well: see the documentation for Icss::Meta::Type.
34
+ #
35
+ # For example, one may define a simple HelloWorld protocol with:
36
+ #
37
+ # {
38
+ # "namespace": "com.acme",
39
+ # "protocol": "HelloWorld",
40
+ # "doc": "Protocol Greetings",
41
+ # "types": [
42
+ # { "name": "Greeting",
43
+ # "type": "record",
44
+ # "fields": [ {"name": "message", "type": "string"} ]},
45
+ # { "name": "Curse",
46
+ # "type": "error",
47
+ # "fields": [ {"name": "message", "type": "string"} ]}
48
+ # ],
49
+ # "messages": {
50
+ # "hello": {
51
+ # "doc": "Say hello.",
52
+ # "request": [{"name": "greeting", "type": "Greeting" }],
53
+ # "response": "Greeting",
54
+ # "errors": ["Curse"]
55
+ # }
56
+ # }
57
+ # }
58
+ #
59
+ class Protocol
60
+ include Icss::ReceiverModel
61
+ include Icss::ReceiverModel::ActsAsCatalog
62
+
63
+ field :protocol, String, :required => true, :validates => { :format => { :with => /\A[A-Za-z_]\w*\Z/, :message => "must start with [A-Za-z_] and contain only [A-Za-z0-9_]." } }
64
+ alias_method :basename, :protocol
65
+ field :namespace, String, :required => true, :validates => { :format => { :with => /\A([A-Za-z_]\w*\.?)+\Z/, :message => "Segments that start with [A-Za-z_] and contain only [A-Za-z0-9_], joined by '.'dots" } }
66
+ field :title, String
67
+ field :doc, String
68
+ #
69
+ field :types, Array, :items => Icss::Meta::TypeFactory, :default => []
70
+ field :_doc_hints, Hash, :default => {}
71
+
72
+ field :messages, Hash, :values => Icss::Meta::Message, :default => {}
73
+ field :data_assets, Array, :items => Icss::Meta::DataAsset, :default => []
74
+ field :code_assets, Array, :items => Icss::Meta::CodeAsset, :default => []
75
+ field :targets, Hash, :values => Icss::TargetListFactory, :default => {}, :merge_as => :hash_of_arrays
76
+
77
+ field :tags, Array, :items => String, :default => []
78
+ field :categories, Array, :items => String, :default => []
79
+ field :license_id, String
80
+ field :credits, Hash, :values=> String, :default => {} # hash of source_ids
81
+
82
+ def license
83
+ Icss::Meta::License.find(license_id) unless license_id.blank?
84
+ end
85
+
86
+ def sources
87
+ @sources ||= credits.inject(Hash.new){|hash, credit| hash[credit[0].to_sym] = Icss::Meta::Source.find(credit[1]); hash }
88
+ end
89
+
90
+ field :under_consideration, Boolean
91
+ field :update_frequency, String, :validates => { :format => { :with => /daily|weekly|monthly|quarterly|never/ }, :allow_blank => true }
92
+ rcvr_remaining :_extra_params
93
+
94
+ after_receive(:parent_my_messages) do |hsh|
95
+ # Set each message's protocol to self, and if the basename wasn't given, set
96
+ # it using the message's hash key.
97
+ self.messages.each{|msg_name, msg| msg.protocol = self; msg.basename ||= msg_name }
98
+ end
99
+ after_receive(:warn_if_invalid) do |hsh|
100
+ warn errors.inspect unless valid?
101
+ warn "Extra params #{_extra_params.keys.inspect} given to #{self.fullname}" if _extra_params.present?
102
+ end
103
+ after_receive(:declare_core_types) do |hsh|
104
+ self.types.each{|type| type.respond_to?(:_schema) && (type._schema.is_core = (self.fullname == "icss.core.typedefs")) }
105
+ end
106
+ after_receive(:fix_legacy_catalog_info) do
107
+ if targets[:catalog].present?
108
+ catalog = targets[:catalog].first
109
+ if self.title.blank? then self.title = catalog.title ; end
110
+ if self.tags.blank? then self.tags = catalog.tags ; end
111
+ if self.doc.blank? then self.doc = catalog.description; end
112
+ end
113
+ end
114
+
115
+ # String: namespace.basename
116
+ def fullname
117
+ [namespace, basename].compact.join(".")
118
+ end
119
+
120
+ # a / separated version of the fullname, with no / at start
121
+ def path
122
+ fullname.gsub('.', '/')
123
+ end
124
+
125
+ def find_message nm
126
+ return if messages.blank?
127
+ nm = nm.to_s.gsub("/", ".").split(".").last
128
+ messages[nm]
129
+ end
130
+
131
+ def receive_types(types)
132
+ # this is a horrible, horrible kludge so that types with simple names ('bob') can become
133
+ # properly namespaced ('foo.bar.bob') even when they haven't met their parents (and even
134
+ # where the calls to receive types are nested/recursive)
135
+ Icss::Meta::TypeFactory.with_namespace(namespace) do
136
+ super(types)
137
+ end
138
+ end
139
+
140
+ def receive_messages(types)
141
+ # this is a horrible, horrible kludge so that messages with simple names ('do_bob') can become
142
+ # properly namespaced ('foo.bar.do_bob') even when they haven't met their parents (and even
143
+ # where the calls to receive_messages are nested/recursive)
144
+ Icss::Meta::TypeFactory.with_namespace(namespace) do
145
+ super(types)
146
+ end
147
+ end
148
+
149
+ def receive_protocol(nm)
150
+ name_segs = nm.to_s.gsub("/", ".").split(".")
151
+ self.protocol = name_segs.pop
152
+ self.namespace = name_segs.join('.') if name_segs.present?
153
+ end
154
+
155
+ def receive_targets(tgts)
156
+ return unless tgts.present?
157
+ self.targets ||= {}
158
+ tgts.symbolize_keys!.each do |target_name, target_info_list|
159
+ targets[target_name] = TargetListFactory.receive(target_info_list, target_name) # array of targets
160
+ end
161
+ targets
162
+ end
163
+
164
+ def self.catalog_sections
165
+ ['core', 'datasets', 'old']
166
+ end
167
+
168
+ def to_hash()
169
+ {
170
+ :namespace => @namespace, # use accessor so unset namespace isn't given
171
+ :protocol => protocol,
172
+ :license_id => license_id,
173
+ :credits => credits,
174
+ :tags => tags,
175
+ :categories => categories,
176
+ :doc => doc,
177
+ :types => (types && types.map(&:to_schema)),
178
+ :messages => messages.inject({}){|h,(k,v)| h[k.to_sym] = v.to_hash; h },
179
+ :data_assets => data_assets.map(&:to_hash).map(&:compact_blank),
180
+ :code_assets => code_assets.map(&:to_hash).map(&:compact_blank),
181
+ :update_frequency => update_frequency,
182
+ :under_consideration => under_consideration,
183
+ :targets => targets_to_hash,
184
+ }.reject{|k,v| v.nil? }
185
+ end
186
+
187
+ def targets_to_hash
188
+ return unless targets
189
+ targets.inject({}) do |hsh,(k,targs)|
190
+ hsh[k] = targs.map(&:to_hash).map(&:compact_blank) ; hsh
191
+ end
192
+ end
193
+
194
+ # This will cause funny errors when it is an element of something that's to_json'ed
195
+ def to_json(*args) to_hash.to_json(*args) ; end
196
+ end
197
+ end
198
+
199
+ end