shale 0.2.2 → 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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/README.md +366 -8
  4. data/exe/shaleb +123 -0
  5. data/lib/shale/adapter/json.rb +7 -2
  6. data/lib/shale/adapter/nokogiri.rb +48 -12
  7. data/lib/shale/adapter/ox.rb +28 -4
  8. data/lib/shale/adapter/rexml.rb +56 -13
  9. data/lib/shale/attribute.rb +7 -1
  10. data/lib/shale/error.rb +12 -0
  11. data/lib/shale/mapper.rb +17 -15
  12. data/lib/shale/mapping/descriptor/dict.rb +57 -0
  13. data/lib/shale/mapping/descriptor/xml.rb +43 -0
  14. data/lib/shale/mapping/descriptor/xml_namespace.rb +37 -0
  15. data/lib/shale/mapping/{key_value.rb → dict.rb} +8 -6
  16. data/lib/shale/mapping/validator.rb +51 -0
  17. data/lib/shale/mapping/xml.rb +86 -15
  18. data/lib/shale/schema/json_compiler/boolean.rb +21 -0
  19. data/lib/shale/schema/json_compiler/date.rb +21 -0
  20. data/lib/shale/schema/json_compiler/float.rb +21 -0
  21. data/lib/shale/schema/json_compiler/integer.rb +21 -0
  22. data/lib/shale/schema/json_compiler/object.rb +85 -0
  23. data/lib/shale/schema/json_compiler/property.rb +70 -0
  24. data/lib/shale/schema/json_compiler/string.rb +21 -0
  25. data/lib/shale/schema/json_compiler/time.rb +21 -0
  26. data/lib/shale/schema/json_compiler/utils.rb +52 -0
  27. data/lib/shale/schema/json_compiler/value.rb +13 -0
  28. data/lib/shale/schema/json_compiler.rb +333 -0
  29. data/lib/shale/schema/json_generator/base.rb +41 -0
  30. data/lib/shale/schema/json_generator/boolean.rb +23 -0
  31. data/lib/shale/schema/json_generator/collection.rb +39 -0
  32. data/lib/shale/schema/json_generator/date.rb +23 -0
  33. data/lib/shale/schema/json_generator/float.rb +23 -0
  34. data/lib/shale/schema/json_generator/integer.rb +23 -0
  35. data/lib/shale/schema/json_generator/object.rb +40 -0
  36. data/lib/shale/schema/json_generator/ref.rb +28 -0
  37. data/lib/shale/schema/json_generator/schema.rb +59 -0
  38. data/lib/shale/schema/json_generator/string.rb +23 -0
  39. data/lib/shale/schema/json_generator/time.rb +23 -0
  40. data/lib/shale/schema/json_generator/value.rb +23 -0
  41. data/lib/shale/schema/json_generator.rb +165 -0
  42. data/lib/shale/schema/xml_generator/attribute.rb +41 -0
  43. data/lib/shale/schema/xml_generator/complex_type.rb +70 -0
  44. data/lib/shale/schema/xml_generator/element.rb +55 -0
  45. data/lib/shale/schema/xml_generator/import.rb +46 -0
  46. data/lib/shale/schema/xml_generator/ref_attribute.rb +37 -0
  47. data/lib/shale/schema/xml_generator/ref_element.rb +39 -0
  48. data/lib/shale/schema/xml_generator/schema.rb +121 -0
  49. data/lib/shale/schema/xml_generator/typed_attribute.rb +46 -0
  50. data/lib/shale/schema/xml_generator/typed_element.rb +46 -0
  51. data/lib/shale/schema/xml_generator.rb +315 -0
  52. data/lib/shale/schema.rb +70 -0
  53. data/lib/shale/type/boolean.rb +2 -2
  54. data/lib/shale/type/composite.rb +78 -72
  55. data/lib/shale/type/date.rb +35 -2
  56. data/lib/shale/type/float.rb +2 -2
  57. data/lib/shale/type/integer.rb +2 -2
  58. data/lib/shale/type/string.rb +2 -2
  59. data/lib/shale/type/time.rb +35 -2
  60. data/lib/shale/type/{base.rb → value.rb} +18 -7
  61. data/lib/shale/utils.rb +18 -2
  62. data/lib/shale/version.rb +1 -1
  63. data/lib/shale.rb +10 -10
  64. data/shale.gemspec +6 -2
  65. metadata +53 -13
  66. data/lib/shale/mapping/base.rb +0 -32
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
3
+ require_relative 'descriptor/xml'
4
+ require_relative 'descriptor/xml_namespace'
5
+ require_relative 'validator'
4
6
 
5
7
  module Shale
6
8
  module Mapping
7
- class Xml < Base
9
+ class Xml
8
10
  # Return elements mapping hash
9
11
  #
10
12
  # @return [Hash]
@@ -26,6 +28,31 @@ module Shale
26
28
  # @api private
27
29
  attr_reader :content
28
30
 
31
+ # Return default namespace
32
+ #
33
+ # @return [Shale::Mapping::Descriptor::XmlNamespace]
34
+ #
35
+ # @api private
36
+ attr_reader :default_namespace
37
+
38
+ # Return unprefixed root
39
+ #
40
+ # @return [String]
41
+ #
42
+ # @api private
43
+ def unprefixed_root
44
+ @root
45
+ end
46
+
47
+ # Return prefixed root
48
+ #
49
+ # @return [String]
50
+ #
51
+ # @api private
52
+ def prefixed_root
53
+ [default_namespace.prefix, @root].compact.join(':')
54
+ end
55
+
29
56
  # Initialize instance
30
57
  #
31
58
  # @api private
@@ -35,32 +62,65 @@ module Shale
35
62
  @attributes = {}
36
63
  @content = nil
37
64
  @root = ''
65
+ @default_namespace = Descriptor::XmlNamespace.new
38
66
  end
39
67
 
40
68
  # Map element to attribute
41
69
  #
42
70
  # @param [String] element Document's element
43
- # @param [Symbol] to Object's attribute
71
+ # @param [Symbol, nil] to Object's attribute
72
+ # @param [Hash, nil] using
73
+ # @param [String, nil] namespace
74
+ # @param [String, nil] prefix
44
75
  #
45
76
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
46
77
  #
47
78
  # @api private
48
- def map_element(element, to: nil, using: nil)
49
- validate_arguments(element, to, using)
50
- @elements[element] = to || using
79
+ def map_element(element, to: nil, using: nil, namespace: :undefined, prefix: :undefined)
80
+ Validator.validate_arguments(element, to, using)
81
+ Validator.validate_namespace(element, namespace, prefix)
82
+
83
+ if namespace == :undefined && prefix == :undefined
84
+ nsp = default_namespace.name
85
+ pfx = default_namespace.prefix
86
+ else
87
+ nsp = namespace
88
+ pfx = prefix
89
+ end
90
+
91
+ namespaced_element = [nsp, element].compact.join(':')
92
+
93
+ @elements[namespaced_element] = Descriptor::Xml.new(
94
+ name: element,
95
+ attribute: to,
96
+ methods: using,
97
+ namespace: Descriptor::XmlNamespace.new(nsp, pfx)
98
+ )
51
99
  end
52
100
 
53
101
  # Map document's attribute to object's attribute
54
102
  #
55
103
  # @param [String] attribute Document's attribute
56
- # @param [Symbol] to Object's attribute
104
+ # @param [Symbol, nil] to Object's attribute
105
+ # @param [Hash, nil] using
106
+ # @param [String, nil] namespace
107
+ # @param [String, nil] prefix
57
108
  #
58
109
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
59
110
  #
60
111
  # @api private
61
- def map_attribute(attribute, to: nil, using: nil)
62
- validate_arguments(attribute, to, using)
63
- @attributes[attribute] = to || using
112
+ def map_attribute(attribute, to: nil, using: nil, namespace: nil, prefix: nil)
113
+ Validator.validate_arguments(attribute, to, using)
114
+ Validator.validate_namespace(attribute, namespace, prefix)
115
+
116
+ namespaced_attribute = [namespace, attribute].compact.join(':')
117
+
118
+ @attributes[namespaced_attribute] = Descriptor::Xml.new(
119
+ name: attribute,
120
+ attribute: to,
121
+ methods: using,
122
+ namespace: Descriptor::XmlNamespace.new(namespace, prefix)
123
+ )
64
124
  end
65
125
 
66
126
  # Map document's content to object's attribute
@@ -72,15 +132,24 @@ module Shale
72
132
  @content = to
73
133
  end
74
134
 
75
- # Name document's element
135
+ # Set the name for root element
136
+ #
137
+ # @param [String] value root's name
76
138
  #
77
- # @param [String, nil] value Document's element name
139
+ # @api private
140
+ def root(value)
141
+ @root = value
142
+ end
143
+
144
+ # Set default namespace for root element
78
145
  #
79
- # @return [Stirng, nil]
146
+ # @param [String] name
147
+ # @param [String] prefix
80
148
  #
81
149
  # @api private
82
- def root(value = nil)
83
- value.nil? ? @root : @root = value
150
+ def namespace(name, prefix)
151
+ @default_namespace.name = name
152
+ @default_namespace.prefix = prefix
84
153
  end
85
154
 
86
155
  # @api private
@@ -89,6 +158,8 @@ module Shale
89
158
  @attributes = other.instance_variable_get('@attributes').dup
90
159
  @content = other.instance_variable_get('@content').dup
91
160
  @root = other.instance_variable_get('@root').dup
161
+ @default_namespace = other.instance_variable_get('@default_namespace').dup
162
+
92
163
  super
93
164
  end
94
165
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Schema
5
+ class JSONCompiler
6
+ # Class that maps Schema type to Shale Boolean type
7
+ #
8
+ # @api private
9
+ class Boolean
10
+ # Return name of the Shale type
11
+ #
12
+ # @return [String]
13
+ #
14
+ # @api private
15
+ def name
16
+ 'Shale::Type::Boolean'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Schema
5
+ class JSONCompiler
6
+ # Class that maps Schema type to Shale Date type
7
+ #
8
+ # @api private
9
+ class Date
10
+ # Return name of the Shale type
11
+ #
12
+ # @return [String]
13
+ #
14
+ # @api private
15
+ def name
16
+ 'Shale::Type::Date'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Schema
5
+ class JSONCompiler
6
+ # Class that maps Schema type to Shale Float type
7
+ #
8
+ # @api private
9
+ class Float
10
+ # Return name of the Shale type
11
+ #
12
+ # @return [String]
13
+ #
14
+ # @api private
15
+ def name
16
+ 'Shale::Type::Float'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Schema
5
+ class JSONCompiler
6
+ # Class that maps Schema type to Shale Integer type
7
+ #
8
+ # @api private
9
+ class Integer
10
+ # Return name of the Shale type
11
+ #
12
+ # @return [String]
13
+ #
14
+ # @api private
15
+ def name
16
+ 'Shale::Type::Integer'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'utils'
4
+
5
+ module Shale
6
+ module Schema
7
+ class JSONCompiler
8
+ # Class representing Shale's comosite type
9
+ #
10
+ # @api private
11
+ class Object
12
+ # Return id
13
+ #
14
+ # @return [String]
15
+ #
16
+ # @api private
17
+ attr_reader :id
18
+
19
+ # Return properties
20
+ #
21
+ # @return [Array<Shale::Schema::JSONCompiler::Property>]
22
+ #
23
+ # @api private
24
+ attr_reader :properties
25
+
26
+ # Name setter
27
+ #
28
+ # @param [String] val
29
+ #
30
+ # @api private
31
+ attr_writer :name
32
+
33
+ # Initialize object
34
+ #
35
+ # @param [String] id
36
+ # @param [String] name
37
+ #
38
+ # @api private
39
+ def initialize(id, name)
40
+ @id = id
41
+ @name = name
42
+ @properties = []
43
+ end
44
+
45
+ # Return name
46
+ #
47
+ # @return [String]
48
+ #
49
+ # @api private
50
+ def name
51
+ Utils.classify(@name)
52
+ end
53
+
54
+ # Return file name
55
+ #
56
+ # @return [String]
57
+ #
58
+ # @api private
59
+ def file_name
60
+ Utils.snake_case(@name)
61
+ end
62
+
63
+ # Return references
64
+ #
65
+ # @return [Array<Shale::Schema::JSONCompiler::Property>]
66
+ #
67
+ # @api private
68
+ def references
69
+ @properties
70
+ .filter { |e| e.type.is_a?(self.class) && e.type != self }
71
+ .uniq { |e| e.type.id }
72
+ end
73
+
74
+ # Add property to Object
75
+ #
76
+ # @param [Shale::Schema::JSONCompiler::Property] property
77
+ #
78
+ # @api private
79
+ def add_property(property)
80
+ @properties << property
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'utils'
4
+
5
+ module Shale
6
+ module Schema
7
+ class JSONCompiler
8
+ # Class representing Shale's property
9
+ #
10
+ # @api private
11
+ class Property
12
+ # Return property's name
13
+ #
14
+ # @return [String]
15
+ #
16
+ # @api private
17
+ attr_reader :property_name
18
+
19
+ # Return attribute's name
20
+ #
21
+ # @return [String]
22
+ #
23
+ # @api private
24
+ attr_reader :attribute_name
25
+
26
+ # Return types's name
27
+ #
28
+ # @return [String]
29
+ #
30
+ # @api private
31
+ attr_reader :type
32
+
33
+ # Initialize Property object
34
+ #
35
+ # @param [String] name
36
+ # @param [Shale::Schema::JsonCompiler::Type] type
37
+ # @param [true, false] collection
38
+ # @param [Object] default
39
+ #
40
+ # @api private
41
+ def initialize(name, type, collection, default)
42
+ @property_name = name
43
+ @attribute_name = Utils.snake_case(name)
44
+ @type = type
45
+ @collection = collection
46
+ @default = default
47
+ end
48
+
49
+ # Return whether property is a collection
50
+ #
51
+ # @return [true, false]
52
+ #
53
+ # @api private
54
+ def collection?
55
+ @collection
56
+ end
57
+
58
+ # Return default value
59
+ #
60
+ # @return [nil, Object]
61
+ #
62
+ # @api private
63
+ def default
64
+ return if collection?
65
+ @default.is_a?(::String) ? @default.dump : @default
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Schema
5
+ class JSONCompiler
6
+ # Class that maps Schema type to Shale String type
7
+ #
8
+ # @api private
9
+ class String
10
+ # Return name of the Shale type
11
+ #
12
+ # @return [String]
13
+ #
14
+ # @api private
15
+ def name
16
+ 'Shale::Type::String'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Schema
5
+ class JSONCompiler
6
+ # Class that maps Schema type to Shale Time type
7
+ #
8
+ # @api private
9
+ class Time
10
+ # Return name of the Shale type
11
+ #
12
+ # @return [String]
13
+ #
14
+ # @api private
15
+ def name
16
+ 'Shale::Type::Time'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Schema
5
+ class JSONCompiler
6
+ # Module with utility functions
7
+ #
8
+ # @api private
9
+ module Utils
10
+ # Convert string to Ruby's class naming convention
11
+ #
12
+ # @param [String] val
13
+ #
14
+ # @example
15
+ # Shale::Schema::JSONCompiler.classify('foobar')
16
+ # # => 'Foobar'
17
+ #
18
+ # @api private
19
+ def self.classify(str)
20
+ str = str.to_s.sub(/.*\./, '')
21
+
22
+ str = str.sub(/^[a-z\d]*/) { |match| match.capitalize || match }
23
+
24
+ str.gsub(%r{(?:_|(/))([a-z\d]*)}i) do
25
+ word = Regexp.last_match(2)
26
+ substituted = word.capitalize || word
27
+ Regexp.last_match(1) ? "::#{substituted}" : substituted
28
+ end
29
+ end
30
+
31
+ # Convert string to snake case
32
+ #
33
+ # @param [String] val
34
+ #
35
+ # @example
36
+ # Shale::Schema::JSONCompiler.snake_case('FooBar')
37
+ # # => 'foo_bar'
38
+ #
39
+ # @api private
40
+ def self.snake_case(str)
41
+ return str.to_s unless /[A-Z-]|::/.match?(str)
42
+ word = str.to_s.gsub('::', '/')
43
+ word = word.gsub(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) do
44
+ "#{Regexp.last_match(1) || Regexp.last_match(2)}_"
45
+ end
46
+ word = word.tr('-', '_')
47
+ word.downcase
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Schema
5
+ class JSONCompiler
6
+ class Value
7
+ def name
8
+ 'Shale::Type::Value'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end