sdl-ng 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.rspec +2 -0
  4. data/.yard_redcarpet_ext +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +13 -0
  7. data/README.md +454 -0
  8. data/Rakefile +16 -0
  9. data/bin/process_service_descriptions +102 -0
  10. data/examples/services/google_drive_for_business.service.rb +50 -0
  11. data/examples/services/salesforce_sales_cloud.service.rb +51 -0
  12. data/examples/translations/en.yml +184 -0
  13. data/examples/vocabulary/base/base.sdl.rb +8 -0
  14. data/examples/vocabulary/base/location.sdl.rb +5 -0
  15. data/examples/vocabulary/crf/characteristics.sdl.rb +25 -0
  16. data/examples/vocabulary/crf/charging.sdl.rb +8 -0
  17. data/examples/vocabulary/crf/compliance.sdl.rb +35 -0
  18. data/examples/vocabulary/crf/delivery.sdl.rb +22 -0
  19. data/examples/vocabulary/crf/dynamics.sdl.rb +6 -0
  20. data/examples/vocabulary/crf/interop.sdl.rb +54 -0
  21. data/examples/vocabulary/crf/optimizing.sdl.rb +15 -0
  22. data/examples/vocabulary/crf/portability.sdl.rb +25 -0
  23. data/examples/vocabulary/crf/protection.sdl.rb +8 -0
  24. data/examples/vocabulary/crf/reliability.sdl.rb +1 -0
  25. data/examples/vocabulary/crf/reputation.sdl.rb +3 -0
  26. data/lib/sdl.rb +17 -0
  27. data/lib/sdl/base.rb +20 -0
  28. data/lib/sdl/base/fact.rb +11 -0
  29. data/lib/sdl/base/property.rb +34 -0
  30. data/lib/sdl/base/service.rb +13 -0
  31. data/lib/sdl/base/service_compendium.rb +130 -0
  32. data/lib/sdl/base/type.rb +66 -0
  33. data/lib/sdl/exporters.rb +9 -0
  34. data/lib/sdl/exporters/exporter.rb +19 -0
  35. data/lib/sdl/exporters/markdown_service_exporter.rb +5 -0
  36. data/lib/sdl/exporters/rdf_exporter.rb +34 -0
  37. data/lib/sdl/exporters/rdf_mapping.rb +48 -0
  38. data/lib/sdl/exporters/schema_exporter.rb +9 -0
  39. data/lib/sdl/exporters/service_exporter.rb +9 -0
  40. data/lib/sdl/exporters/xml_mapping.rb +51 -0
  41. data/lib/sdl/exporters/xml_service_exporter.rb +37 -0
  42. data/lib/sdl/exporters/xsd_schema_exporter.rb +94 -0
  43. data/lib/sdl/receivers.rb +22 -0
  44. data/lib/sdl/receivers/fact_receiver.rb +15 -0
  45. data/lib/sdl/receivers/service_receiver.rb +63 -0
  46. data/lib/sdl/receivers/type_instance_receiver.rb +86 -0
  47. data/lib/sdl/receivers/type_receiver.rb +87 -0
  48. data/lib/sdl/translations/en.yml +9 -0
  49. data/lib/sdl/types.rb +19 -0
  50. data/lib/sdl/types/sdl_datetime.rb +10 -0
  51. data/lib/sdl/types/sdl_default_type.rb +13 -0
  52. data/lib/sdl/types/sdl_description.rb +10 -0
  53. data/lib/sdl/types/sdl_duration.rb +12 -0
  54. data/lib/sdl/types/sdl_number.rb +10 -0
  55. data/lib/sdl/types/sdl_string.rb +10 -0
  56. data/lib/sdl/types/sdl_type.rb +31 -0
  57. data/lib/sdl/types/sdl_url.rb +12 -0
  58. data/lib/sdl/util.rb +4 -0
  59. data/lib/sdl/util/documentation.rb +80 -0
  60. data/lib/sdl/util/nokogiri.rb +28 -0
  61. data/lib/sdl/util/verbs.rb +3 -0
  62. data/lib/sdl/version.rb +3 -0
  63. data/sdl-ng.gemspec +34 -0
  64. data/spec/documentation_spec.rb +64 -0
  65. data/spec/fact_type_instance_definition_spec.rb +188 -0
  66. data/spec/property_definitions_spec.rb +44 -0
  67. data/spec/service_compendium_spec.rb +90 -0
  68. data/spec/service_definition_spec.rb +81 -0
  69. data/spec/shared_test_compendium.rb +65 -0
  70. data/spec/spec_helper.rb +10 -0
  71. metadata +291 -0
@@ -0,0 +1,9 @@
1
+ require_relative 'exporters/xml_mapping'
2
+ require_relative 'exporters/exporter'
3
+ require_relative 'exporters/schema_exporter'
4
+ require_relative 'exporters/service_exporter'
5
+ require_relative 'exporters/xsd_schema_exporter'
6
+ require_relative 'exporters/xml_service_exporter'
7
+ require_relative 'exporters/rdf_mapping'
8
+ require_relative 'exporters/rdf_exporter'
9
+ require_relative 'exporters/markdown_service_exporter'
@@ -0,0 +1,19 @@
1
+ module SDL
2
+ module Exporters
3
+ class Exporter
4
+ attr :compendium
5
+ attr :options
6
+
7
+ def initialize(compendium, options = {})
8
+ @compendium = compendium
9
+ @options = options
10
+ end
11
+
12
+ def export_to_file(path, content)
13
+ File.open(path, 'w') do |f|
14
+ f.write(content)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ class SDL::Exporters::MarkdownServiceExporter < SDL::Exporters::ServiceExporter
2
+ def export_service(service)
3
+ "Not implemented yet"
4
+ end
5
+ end
@@ -0,0 +1,34 @@
1
+ require 'rdf'
2
+ require 'rdf/rdfxml'
3
+
4
+ module SDL
5
+ module Exporters
6
+ class RDFExporter < ServiceExporter
7
+ @@s = RDF::Vocabulary.new('http://www.open-service-compendium.org/')
8
+
9
+ def export_service(service)
10
+ graph = RDF::Graph.new
11
+
12
+ service.facts.each do |fact|
13
+ graph << [RDF::URI.new(service.uri), @@s["has_#{fact.class.local_name.underscore}"], RDF::URI.new(fact.uri)]
14
+
15
+ expand_properties(fact, graph)
16
+ end
17
+
18
+ graph.dump(:rdf)
19
+ end
20
+
21
+ def expand_properties(type_instance, graph)
22
+ type_instance.property_values.each do |property, value|
23
+ [value].flatten.each do |v|
24
+ graph << [RDF::URI.new(type_instance.uri), @@s["#{property.name.underscore}"], v.rdf_object] unless v.nil?
25
+ end
26
+
27
+ if property.type < SDL::Base::Type
28
+ [value].flatten.each do |v| expand_properties(v, graph) end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,48 @@
1
+ require 'rdf'
2
+ require 'active_support/inflector'
3
+
4
+ [String, Fixnum, Nokogiri::XML::Element].each do |klass|
5
+ klass.class_eval do
6
+ def rdf_object
7
+ RDF::Literal.new(self)
8
+ end
9
+ end
10
+ end
11
+
12
+ module SDL
13
+ module Base
14
+ class Fact
15
+ class << self
16
+ def uri
17
+ "http://www.open-service-compendium.org/types/#{@local_name}"
18
+ end
19
+ end
20
+
21
+ def uri
22
+ "#{service.uri}/#{self.class.local_name.underscore}-#{hash}"
23
+ end
24
+ end
25
+
26
+ class Type
27
+ class << self
28
+ def uri
29
+ "http://www.open-service-compendium.org/types/#{@local_name}"
30
+ end
31
+ end
32
+
33
+ def uri
34
+ self.class.uri + '/' + hash.to_s
35
+ end
36
+
37
+ def rdf_object
38
+ RDF::URI.new(uri)
39
+ end
40
+ end
41
+
42
+ class Service
43
+ def uri
44
+ "http://www.open-service-compendium.org/services/#{@symbolic_name}"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ module SDL
2
+ module Exporters
3
+ class SchemaExporter < Exporter
4
+ def export_schema_to_file(path)
5
+ export_to_file path, export_schema
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module SDL
2
+ module Exporters
3
+ class ServiceExporter < Exporter
4
+ def export_service_to_file(service, path)
5
+ export_to_file path, export_service(service)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ module SDL
2
+ module Base
3
+ class Property
4
+ def xsd_element_name
5
+ if multi?
6
+ @name.singularize
7
+ else
8
+ @name
9
+ end
10
+ end
11
+ end
12
+
13
+ class Type
14
+ class << self
15
+ def xsd_element_name
16
+ local_name.camelize(:lower)
17
+ end
18
+
19
+ def xsd_type_name
20
+ local_name
21
+ end
22
+
23
+ def xsd_type_qname
24
+ 'sdl:' + xsd_type_name
25
+ end
26
+ end
27
+ end
28
+
29
+ class Fact
30
+ class << self
31
+ def xsd_type_name
32
+ "#{local_name}Fact"
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ module Types
39
+ module SDLType
40
+ module ClassMethods
41
+ def xml_type
42
+ if self < SDL::Base::Type
43
+ wrapped_type.xsd_type_name
44
+ else
45
+ 'ns:string'
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,37 @@
1
+ module SDL
2
+ module Exporters
3
+ class XMLServiceExporter < ServiceExporter
4
+ def export_service(service)
5
+ builder = Nokogiri::XML::Builder.new do |xml|
6
+ xml.service('xmlns' => 'http://www.open-service-compendium.org') do
7
+ service.facts.each do |fact|
8
+ xml.send(fact.class.xsd_element_name + '_') do
9
+ serialize_type_instance fact, xml
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ builder.to_xml
16
+ end
17
+
18
+ def serialize_type_instance(type_instance, xml)
19
+ type_instance.property_values.each do |property, value|
20
+ [value].flatten.each do |v|
21
+ if v.class < SDL::Base::Type
22
+ xml.send(property.xsd_element_name + '_', (!value.is_a?(Array) && value.identifier) ? {'identifier' => value.identifier.to_s} : {}) do
23
+ v.annotations.each do |annotation|
24
+ xml.annotation annotation
25
+ end
26
+ xml.documentation v.documentation if (!value.is_a?(Array) && value.identifier)
27
+ serialize_type_instance(v, xml)
28
+ end
29
+ else
30
+ xml.send(property.xsd_element_name + '_', v)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,94 @@
1
+ require 'active_support/inflector'
2
+ require 'nokogiri'
3
+
4
+ module SDL
5
+ module Exporters
6
+ ##
7
+ # The XSD schema exporter creates an XML Schema Definition for consuming service descriptions using the XML provided
8
+ # by the XMLServiceExporter.
9
+ #
10
+ # The schema consists of the following main components:
11
+ # - The definition of the root node, i.e., a service. The service contains an arbitrary number of elements of
12
+ # service fact types.
13
+ # - The definition of service fact classes and SDL types
14
+ # - The definition of a type base, containing annotations and documentation
15
+ class XSDSchemaExporter < SchemaExporter
16
+ def export_schema
17
+ export_schema_xml.to_xml
18
+ end
19
+
20
+ def export_schema_xml
21
+ Nokogiri::XML::Builder.new do |xml|
22
+ xml['ns'].schema('xmlns' => 'http://www.open-service-compendium.org', 'targetNamespace' => 'http://www.open-service-compendium.org', 'xmlns:ns' => 'http://www.w3.org/2001/XMLSchema', 'elementFormDefault' => 'qualified') do
23
+ xml['ns'].element :name => 'service' do
24
+ document(xml, I18n.t('sdl.xml.service_root'))
25
+ xml['ns'].complexType do
26
+ xml['ns'].choice :maxOccurs => 'unbounded' do
27
+ @compendium.fact_classes.each do |fact_class|
28
+ xml['ns'].element :name => fact_class.xsd_element_name, :type => fact_class.xsd_type_name do
29
+ document(xml, fact_class.documentation)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ xml['ns'].complexType :name => 'SDLTypeBase' do
37
+ document(xml, I18n.t('sdl.xml.typebase'))
38
+ xml['ns'].choice do
39
+ xml['ns'].element :name => 'documentation', :minOccurs => 0, :maxOccurs => 'unbounded', :type => 'ns:string' do
40
+ document(xml, I18n.t('sdl.xml.documentation'))
41
+ end
42
+ xml['ns'].element :name => 'annotation', :minOccurs => 0, :maxOccurs => 'unbounded', :type => 'ns:string' do
43
+ document(xml, I18n.t('sdl.xml.annotation'))
44
+ end
45
+ end
46
+ xml['ns'].attribute :name => 'identifier' do
47
+ document(xml, I18n.t('sdl.xml.identifier'))
48
+ end
49
+ end
50
+
51
+ (@compendium.fact_classes + @compendium.types).each do |fact_class|
52
+ xml['ns'].complexType :name => fact_class.xsd_type_name do
53
+ document(xml, fact_class.documentation)
54
+ xml['ns'].complexContent do
55
+ xml['ns'].extension :base => fact_class.is_sub? ? fact_class.superclass.xsd_type_name : 'SDLTypeBase' do
56
+ unless fact_class.properties.empty?
57
+ xml['ns'].sequence do
58
+ fact_class.properties.each do |property|
59
+ extend_property(property, xml) do
60
+ document(xml, property.documentation)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ # Creates an xml element corresponding to the SDL property
74
+ def extend_property(property, xml)
75
+ if property.multi?
76
+ xml['ns'].element :name => property.name.singularize, :type => property.type.xml_type, :minOccurs => 0, :maxOccurs => 'unbounded' do
77
+ yield
78
+ end
79
+ else
80
+ xml['ns'].element :name => property.name, :type => property.type.xml_type, :minOccurs => 0 do
81
+ yield
82
+ end
83
+ end
84
+ end
85
+
86
+ # Shortcut for adding an XSD documentation annotation
87
+ def document(xml, documentation)
88
+ xml['ns'].annotation do
89
+ xml['ns'].documentation documentation
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'receivers/type_instance_receiver'
2
+ require_relative 'receivers/type_receiver'
3
+ require_relative 'receivers/fact_receiver'
4
+ require_relative 'receivers/service_receiver'
5
+
6
+
7
+ module SDL
8
+ module Receivers
9
+ #
10
+ def self.set_value(type_class, type_instance, *property_values, compendium)
11
+ property_values.zip(type_class.properties(true)).each do |value, property|
12
+ if(value.is_a?(Hash))
13
+ TypeInstanceReceiver.new(type_instance, compendium).send(value.keys.first.to_s, value.values.first)
14
+ else
15
+ raise "Specified value '#{value}' for non-existing property." unless property
16
+
17
+ TypeInstanceReceiver.new(type_instance, compendium).send(property.name, value)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module SDL
2
+ module Receivers
3
+ class FactReceiver < TypeReceiver
4
+ def base_class
5
+ SDL::Base::Fact
6
+ end
7
+
8
+ def register_sdltype(type)
9
+ false
10
+ end
11
+
12
+ alias :subfact :subtype
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,63 @@
1
+ require 'verbs'
2
+
3
+ require_relative '../base/service'
4
+
5
+ module SDL
6
+ module Receivers
7
+ class ServiceReceiver
8
+ include ActiveSupport::Inflector
9
+
10
+ attr :service
11
+ attr :compendium
12
+
13
+ def initialize(sym, compendium)
14
+ @service = SDL::Base::Service.new(sym.to_s)
15
+ @compendium = compendium
16
+
17
+ compendium.fact_classes.each do |fact_class|
18
+ define_singleton_method("is_#{fact_class.local_name.underscore.verb.conjugate(:tense => :past, :person => :third, :plurality => :singular, :aspect => :perfective)}") do |*args, &block|
19
+ add_fact fact_class, *args, &block
20
+ end
21
+
22
+ define_singleton_method("has_#{fact_class.local_name.underscore}") do |*args, &block|
23
+ add_fact fact_class, *args, &block
24
+ end
25
+
26
+ define_singleton_method("#{fact_class.local_name.underscore}") do |*args, &block|
27
+ add_fact fact_class, *args, &block
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+ def add_fact(fact_class, *property_values, &block)
34
+ fact_instance = fact_class.new
35
+ fact_instance.service = @service
36
+
37
+ SDL::Receivers.set_value(fact_class, fact_instance, *property_values, @compendium)
38
+
39
+ if block_given?
40
+ SDL::Receivers::TypeInstanceReceiver.new(fact_instance, @compendium).instance_eval &block
41
+ end
42
+
43
+ @service.facts << fact_instance
44
+ end
45
+
46
+ ##
47
+ # Catches calls to methods named similarily to possible predefined type instances
48
+ def method_missing(name, *args)
49
+ possible_type_instances = @compendium.type_instances.map{|k, v| v[name]}.select{|v| v != nil}
50
+
51
+ unless possible_type_instances.nil? || possible_type_instances.empty?
52
+ if possible_type_instances.length > 1
53
+ raise Exception.new("Multiple possibilities for #{name} in #{caller[0]}")
54
+ else
55
+ possible_type_instances[0]
56
+ end
57
+ else
58
+ raise Exception.new("I do not know what to do with '#{name}' in #{caller[0]}")
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,86 @@
1
+ require 'active_support/inflector'
2
+
3
+ module SDL
4
+ module Receivers
5
+ ##
6
+ # Receiver for setting the properties of Type instances
7
+ class TypeInstanceReceiver
8
+ attr_accessor :instance
9
+
10
+ attr_accessor :compendium
11
+
12
+ ##
13
+ # When initialized for a fact or type instance, the receiver creates singleton methods on itself for all
14
+ # properties.
15
+ def initialize(instance, compendium)
16
+ @instance = instance
17
+ @compendium = compendium
18
+
19
+ instance.class.properties(true).each do |property|
20
+ if property.single?
21
+ # Single valued properties are set by their name
22
+ define_singleton_method property.name do |value = nil, &block|
23
+ if value.is_a? Symbol
24
+ value = compendium.type_instances[property.type][value] || raise("Could not find instance :#{value.to_s} in predefined #{property.type.name} types")
25
+ end
26
+
27
+ instance.send "#{property.name}=", value
28
+ end
29
+ else
30
+ # Multi-valued properties are added to by their singular name
31
+ define_singleton_method property.name.singularize do |*property_values, &block|
32
+ existing_list = instance.send "#{property.name}"
33
+
34
+ unless property_values.empty?
35
+ # If there is just one parameter for a multi-valued property setter
36
+ if property_values.length == 1
37
+ # It could be a symbol, which would resolve to a predefined type instance of the same name
38
+ if property_values[0].is_a?(Symbol)
39
+ predefined_value = compendium.type_instances[property.type][property_values[0]]
40
+
41
+ raise "Could not find instance :#{property_values[0]} in predefined #{property.type.name} types" unless predefined_value
42
+
43
+ existing_list << compendium.type_instances[property.type][property_values[0]]
44
+ # Or better: it could already be an instance of the type - e.g. when using the implemented #method_mssing
45
+ elsif property_values[0].is_a? property.type
46
+ existing_list << property_values[0]
47
+ end
48
+ else
49
+ new_list_item = property.type.new
50
+
51
+ SDL::Receivers.set_value(property.type, new_list_item, *property_values, @compendium)
52
+
53
+ self.class.new(new_list_item, @compendium).instance_exec(&block) unless block.nil?
54
+
55
+ existing_list << new_list_item
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def annotation(value)
64
+ @instance.annotations << value
65
+ end
66
+
67
+ ##
68
+ # Catches calls to methods named similarily to possible predefined type instances
69
+ def method_missing(name, *args)
70
+ # Possible type instances are all types of properties of properties of this instance ...
71
+ possible_type_classes = @instance.class.properties.map(&:type).map(&:properties).flatten.map(&:type).select{|type| type.wrapped_type < SDL::Base::Type}
72
+
73
+ # ... and the types of multi-value instances
74
+ possible_type_classes.concat(@instance.class.properties.find_all{|p| p.multi?}.map(&:type))
75
+
76
+ possible_type_instances = @compendium.type_instances.select{|k, v| possible_type_classes.include?(k)}.map{|k, v| v[name]}.select{|v| v != nil}
77
+
78
+ unless possible_type_instances.nil? || possible_type_instances.empty?
79
+ possible_type_instances[0]
80
+ else
81
+ raise Exception.new("I do not know what to do with '#{name}' in #{caller[0]}")
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end