client_for_poslynx 0.1.1 → 0.2.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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NDk4YjBkNTE0MzhlOGU3MThjNDc1MmYxOTA4MWRmZDM4YmU1ZGM4OQ==
4
+ NzJjNDczYjYzYzBiMTE1MDI3YTQ4Mjk1M2Y4OGM3ZTM4YTc5NzdhOA==
5
5
  data.tar.gz: !binary |-
6
- NGNmMTc0ODljNWFlYzE2MmFhMzJkMjhmYmE0NzQ5NWU0NWY0MWUzMg==
6
+ MzgxZGMxZGE4MWQ2ZTc5Yjc3Mjg1MzIzNzJkNDRiZjRkN2M5OGQzZA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MTA1ODAwOTA4YTRlOWM3ZDdmYzhjM2IyYTJmODY4ZDJkMTBjMGM5YWNiZmQ0
10
- YWI3YmIyNjI5MDFmNWY4NTEwYmI3YWY1YWM1Yjc5ZjFiYjg0YTAyM2NmNGNm
11
- MDg0NDQ1ZGQyMGFkYmUzOTc2NDE2YWRhYWMzMDIzODEwYjgxMWU=
9
+ MTMzZTM0OGI5YThhNmI0ODZiNjllN2ZiMjI4OWFlMTM0N2VkYWVlNDRkMTZm
10
+ NWUzNTMwMjJkNTgyODYxMDBlYzI3YWNmMTk4MjMxYmE4YWM3OTExNzQ5MmI5
11
+ MTVkZGVlNmYyODZjNjFhOTM3MzAzZDA1ODJhNjZkNWZjNmU0ODE=
12
12
  data.tar.gz: !binary |-
13
- Mzk4MzMxNWU5ZTFkYmU1NTFmOTZiNjEyMTViZDg0MWY5NTllM2JkNWM5MTI2
14
- ZTNkNGM4NWU5Nzg2NzQzMjliMTdhYzIwMTViNjM1YTQ4NTA2NjBhYzRiNTY5
15
- MzYyZjU4ZmJlNjVkYjE3NTc3M2EwNmJhYWJiNzJlYmYyNTFkNjM=
13
+ NTQwZDEyZGI0YWM4MjExNjBiOGU5M2MxNzcwNDY0M2ZhYmVkZjAwYmI2NzYw
14
+ MjBlZDhmMTM3N2M5ZDA5MDkxZmE3YmNmZDFlZjQwZjNhNmUzN2JmZDc2ZTkx
15
+ ZDI2MmExMDg0ZmVhYTBmNzdkNjlhM2I2ZTlmN2QxZjViYzkxNWY=
data/CHANGELOG CHANGED
@@ -6,3 +6,6 @@ Version 0.1.0
6
6
 
7
7
  Version 0.1.1
8
8
  - Add CHANGELOG file
9
+
10
+ Version 0.2.0
11
+ - Improve API for specifying attribute element mappings.
@@ -1,6 +1,7 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'nokogiri'
3
+ require_relative 'abstract_data/attribute_element_mapping'
4
+ require_relative 'abstract_data/defining_property_mapping'
4
5
 
5
6
  module ClientForPoslynx
6
7
  module Data
@@ -16,22 +17,16 @@ module ClientForPoslynx
16
17
  end
17
18
 
18
19
  def xml_parse(source_xml)
19
- doc = XmlDocument.new( source_xml )
20
- concrete_data_classes = descendants.
21
- reject{ |d| d.name =~ /\bAbstract[A-Z]\w*$/ }.
22
- sort_by{ |d| -d.ancestors.length }
23
- data_class = concrete_data_classes.detect{ |dc|
24
- dc.root_element_name == doc.root_name &&
25
- dc.fits_properties?( doc.property_element_contents )
26
- }
27
- data_class.xml_deserialize(source_xml)
20
+ doc = XmlDocument.from_xml( source_xml )
21
+ data_class = concrete_data_class_for_nokogiri_document( doc )
22
+ data_class.xml_deserialize( source_xml )
28
23
  end
29
24
 
30
25
  def xml_deserialize(xml)
31
- doc = XmlDocument.new(xml)
32
- raise InvalidXmlContentError, "#{root_element_name} root element not found" unless doc.root_name == root_element_name
26
+ doc = XmlDocument.from_xml( xml )
27
+ doc.verify_root_element_name root_element_name
33
28
  instance = load_from_properties( doc.property_element_contents )
34
- instance.source_data = doc.source_xml
29
+ instance.source_data = xml
35
30
  instance
36
31
  end
37
32
 
@@ -48,22 +43,20 @@ module ClientForPoslynx
48
43
  unmatched.empty?
49
44
  end
50
45
 
51
- def defining_element_mappings
52
- @defining_element_mappings ||=
53
- begin
54
- self == AbstractData ?
55
- [] :
56
- superclass.defining_element_mappings + []
57
- end
46
+ def defining_property_mappings
47
+ @defining_property_mappings ||= (
48
+ self == AbstractData ?
49
+ [] :
50
+ superclass.defining_property_mappings + []
51
+ )
58
52
  end
59
53
 
60
54
  def attr_element_mappings
61
- @attr_element_mappings ||=
62
- begin
63
- self == AbstractData ?
64
- [] :
65
- superclass.attr_element_mappings + []
66
- end
55
+ @attr_element_mappings ||= (
56
+ self == AbstractData ?
57
+ [] :
58
+ superclass.attr_element_mappings + []
59
+ )
67
60
  end
68
61
 
69
62
  private
@@ -76,72 +69,63 @@ module ClientForPoslynx
76
69
  @@descendants ||= []
77
70
  end
78
71
 
79
- def defining_element_value(options)
72
+ def concrete_data_class_for_nokogiri_document(doc)
73
+ data_class = concrete_data_classes.detect{ |dc|
74
+ dc.root_element_name == doc.root_name &&
75
+ dc.fits_properties?( doc.property_element_contents )
76
+ }
77
+ end
78
+
79
+ def concrete_data_classes
80
+ descendants.
81
+ reject{ |d| d.name =~ /\bAbstract[A-Z]\w*$/ }.
82
+ sort_by{ |d| -d.ancestors.length }
83
+ end
84
+
85
+ def defining_property_value(options)
80
86
  attribute = options.fetch( :attribute )
81
87
  element = options.fetch( :element )
82
88
  value = options.fetch( :value )
83
- define_singleton_method(attribute) { value }
84
- defining_element_mappings << { attribute: attribute, element: element }
89
+ define_singleton_method( attribute ) { value }
90
+ define_method( attribute ) { value }
91
+ defining_property_mappings << DefiningPropertyMapping.new( attribute: attribute, element: element )
85
92
  end
86
93
 
87
94
  def attr_element_mapping(options)
88
- type = options[:type]
89
- unless type.nil?
90
- raise ArgumentError, "The :type option must be a symbol, but a #{type.class} was given." unless Symbol === type
91
- raise ArgumentError, "#{type.inspect} is not a valid :type option. Must be :array when given." unless type == :array
92
- end
93
- attribute = options.fetch( :attribute )
94
- element = options.fetch( :element )
95
- attr_accessor attribute
96
- attr_element_mappings << options
95
+ mapping = AbstractData::AttributeElementMapping.new( options )
96
+ attr_element_mappings << mapping
97
+ attr_accessor mapping.attribute_name
97
98
  end
98
99
 
99
100
  def verify_defining_properties(property_contents)
100
101
  unmatched = unmatched_defining_properties( property_contents )
101
102
  return if unmatched.empty?
102
- message = unmatched.map{ |mapping|
103
- attribute, el_name = mapping.values_at(:attribute, :element)
104
- defining_value = public_send(attribute)
105
- "#{el_name} child element with \"#{defining_value}\" value not found."
103
+ message = unmatched.map{ |property_mapping|
104
+ defining_mapping = public_send( property_mapping.attribute_name )
105
+ "#{property_mapping.element_name} child element with \"#{defining_mapping}\" value not found."
106
106
  }.join( ' ' )
107
107
  raise InvalidXmlContentError, message
108
108
  end
109
109
 
110
110
  def unmatched_defining_properties(property_contents)
111
111
  unmatched = []
112
- defining_element_mappings.each do |mapping|
113
- attribute, el_name = mapping.values_at(:attribute, :element)
114
- defining_value = public_send(attribute)
115
- unmatched << mapping unless property_contents[el_name] == defining_value
112
+ defining_property_mappings.each do |property_mapping|
113
+ defining_value = public_send( property_mapping.attribute_name )
114
+ unmatched << property_mapping unless property_contents[property_mapping.element_name] == defining_value
116
115
  end
117
116
  unmatched
118
117
  end
119
118
 
120
119
  def select_variable_property_contents(property_contents)
121
- defining_element_names = defining_element_mappings.map{ |mapping| mapping[:element] }
120
+ defining_element_names = defining_property_mappings.map(&:element_name)
122
121
  property_contents.reject{ |name, content| defining_element_names.include?(name) }
123
122
  end
124
123
 
125
124
  def populate_instance_from_properties instance, variable_property_contents
126
125
  variable_property_contents.each do |name, content|
127
- mapping = attr_element_mappings.detect{ |mapping| mapping[:element] == name }
126
+ mapping = attr_element_mappings.detect{ |mapping| mapping.element_name == name }
128
127
  next unless mapping
129
- value = if mapping[:numbered_lines]
130
- template = mapping[:numbered_lines]
131
- [].tap{ |lines|
132
- line_num = 1
133
- while ( content.has_key?(key = template % line_num) )
134
- lines << content[key]
135
- line_num += 1
136
- end
137
- }
138
- elsif mapping[:type] == :array
139
- content.split('|')
140
- else
141
- content
142
- end
143
- attribute = mapping[:attribute]
144
- instance.public_send "#{attribute}=", value
128
+ instance.public_send "#{mapping.attribute_name}=", mapping.value_from_element_content( content)
145
129
  end
146
130
  end
147
131
 
@@ -150,50 +134,28 @@ module ClientForPoslynx
150
134
  attr_accessor :source_data
151
135
 
152
136
  def xml_serialize
153
- doc = Nokogiri::XML::Document.new
154
- root = doc.create_element(self.class.root_element_name)
155
- self.class.defining_element_mappings.each do |mapping|
156
- content = self.class.public_send( mapping[:attribute] )
157
- next unless content
158
- element = doc.create_element( mapping[:element], nil, nil, content )
159
- root.add_child element
160
- end
161
- self.class.attr_element_mappings.each do |mapping|
162
- content = public_send( mapping[:attribute] )
163
- next unless content
164
- element = if mapping[:numbered_lines]
165
- build_numbered_lines_xml_node( doc, mapping[:element], mapping[:numbered_lines], content )
166
- elsif mapping[:type] == :array
167
- build_vertical_bar_separated_list_node( doc, mapping[:element], content )
168
- else
169
- build_text_element_node( doc, mapping[:element], content )
170
- end
171
- root.add_child element
172
- end
173
- doc.root = root
174
- doc.serialize(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
137
+ doc = Data::XmlDocument.with_root_element_name( self.class.root_element_name )
138
+ add_properties_to_xml_document doc
139
+ doc.serialize
175
140
  end
176
141
 
177
142
  private
178
143
 
179
- def build_numbered_lines_xml_node(doc, element_name, line_template, content)
180
- element = doc.create_element( element_name )
181
- [content].flatten.each_with_index do |line_text, idx|
182
- line_num = idx + 1
183
- element_name = line_template % line_num
184
- line_el = doc.create_element( element_name, nil, nil, line_text )
185
- element.add_child line_el
144
+ def add_properties_to_xml_document(doc)
145
+ all_mappings.each do |mapping|
146
+ content = property_attribute_value( mapping )
147
+ next unless content
148
+ doc_content = mapping.xml_doc_content_from_client_content( content )
149
+ doc.add_property_content mapping.element_name, doc_content
186
150
  end
187
- element
188
151
  end
189
152
 
190
- def build_vertical_bar_separated_list_node(doc, element_name, content)
191
- text = [content].flatten * '|'
192
- doc.create_element( element_name, nil, nil, text )
153
+ def all_mappings
154
+ self.class.defining_property_mappings + self.class.attr_element_mappings
193
155
  end
194
156
 
195
- def build_text_element_node(doc, element_name, content)
196
- doc.create_element( element_name, nil, nil, "#{content}" )
157
+ def property_attribute_value( property )
158
+ public_send( property.attribute_name )
197
159
  end
198
160
 
199
161
  end
@@ -0,0 +1,141 @@
1
+ # coding: utf-8
2
+
3
+ require 'nokogiri'
4
+
5
+ module ClientForPoslynx
6
+ module Data
7
+ class AbstractData
8
+
9
+ module AttributeElementMapping
10
+
11
+ class Abstract ; end
12
+ class Text < AttributeElementMapping::Abstract ; end
13
+ class MultiText < AttributeElementMapping::Abstract ; end
14
+ class NumberedLines < AttributeElementMapping::Abstract ; end
15
+
16
+ def self.new(options)
17
+ klass = case
18
+ when options[:multi_text] ; AttributeElementMapping::MultiText
19
+ when options[:numbered_lines] ; AttributeElementMapping::NumberedLines
20
+ else ; AttributeElementMapping::Text
21
+ end
22
+ klass.new( options )
23
+ end
24
+
25
+ class Abstract
26
+ attr_reader :attribute_name, :element_name, :numbered_line_template
27
+
28
+ def numbered_lines? ; @numbered_lines ; end
29
+ def multi_text? ; @multi_text ; end
30
+
31
+ def initialize(options)
32
+ options = options.reject { |k,v| v.nil? }
33
+ @attribute_name = options.fetch( :attribute ) { raise ArgumentError, ':attribute option value must be provided' }
34
+ @element_name = options.fetch( :element ) { raise ArgumentError, ':element option value must be provided' }
35
+ options.delete :attribute ; options.delete :element
36
+ additional_init options
37
+ verify_no_unexpected_unused_options options
38
+ end
39
+
40
+ def text_mapping? ; false ; end
41
+ def multi_text_mapping? ; false ; end
42
+ def numbered_lines_mapping? ; false ; end
43
+
44
+ def value_from_element_content(content)
45
+ raise NotImplementedError
46
+ [].tap{ |lines|
47
+ line_num = 1
48
+ while ( content.has_key?(key = numbered_line_template % line_num) )
49
+ lines << content[key]
50
+ line_num += 1
51
+ end
52
+ }
53
+ end
54
+
55
+ def xml_doc_content_from_client_content(client_content)
56
+ raise NotImplementedError
57
+ end
58
+
59
+ private
60
+
61
+ def verify_no_unexpected_unused_options(unused_options)
62
+ unless unused_options.empty?
63
+ key_list = unused_options.keys.map(&:inspect)
64
+ raise ArgumentError, "Unexpected option(s) #{key_list} supplied"
65
+ end
66
+ end
67
+
68
+ def additional_init(options)
69
+ # Do nothing by default.
70
+ end
71
+ end
72
+
73
+ class Text < AttributeElementMapping::Abstract
74
+ def text_mapping? ; true ; end
75
+
76
+ def value_from_element_content(content)
77
+ content
78
+ end
79
+
80
+ def xml_doc_content_from_client_content(client_content)
81
+ client_content.to_s
82
+ end
83
+ end
84
+
85
+ class MultiText < AttributeElementMapping::Abstract
86
+ def multi_text_mapping? ; true ; end
87
+
88
+ def value_from_element_content(content)
89
+ content.split('|')
90
+ end
91
+
92
+ def xml_doc_content_from_client_content(client_content)
93
+ client_content = [client_content].flatten
94
+ client_content * '|'
95
+ end
96
+
97
+ private
98
+
99
+ def additional_init(options)
100
+ @multi_text = !!options.delete( :multi_text )
101
+ end
102
+ end
103
+
104
+ class NumberedLines < AttributeElementMapping::Abstract
105
+ def numbered_lines_mapping? ; true ; end
106
+
107
+ def value_from_element_content(content)
108
+ [].tap{ |lines|
109
+ line_num = 1
110
+ while ( content.has_key?(key = numbered_line_template % line_num) )
111
+ lines << content[key]
112
+ line_num += 1
113
+ end
114
+ }
115
+ end
116
+
117
+ def xml_doc_content_from_client_content(client_content)
118
+ client_content = [client_content].flatten
119
+ Hash[
120
+ client_content.each_with_index.map { |line_text, idx|
121
+ line_num = idx + 1
122
+ line_element_name = numbered_line_template % line_num
123
+ [ line_element_name, line_text ]
124
+ }
125
+ ]
126
+ end
127
+
128
+ private
129
+
130
+ def additional_init(options)
131
+ numbered_line_name_template = options.delete( :numbered_lines )
132
+ @numbered_lines = !!numbered_line_name_template
133
+ @numbered_line_template = numbered_line_name_template
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+
3
+ module ClientForPoslynx
4
+ module Data
5
+ class AbstractData
6
+
7
+ class DefiningPropertyMapping
8
+ attr_reader :attribute_name, :element_name
9
+
10
+ def initialize(options)
11
+ @attribute_name = options.fetch(:attribute)
12
+ @element_name = options.fetch(:element)
13
+ end
14
+
15
+ def xml_doc_content_from_client_content(client_content)
16
+ client_content
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -8,7 +8,7 @@ module ClientForPoslynx
8
8
 
9
9
  class CreditCardSale < AbstractRequest
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'CCSALE'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'CCSALE'
12
12
 
13
13
  attr_element_mapping attribute: :merchant_supplied_id, element: 'Id'
14
14
  attr_element_mapping attribute: :client_id, element: 'ClientId'
@@ -8,7 +8,7 @@ module ClientForPoslynx
8
8
 
9
9
  class DebitCardSale < AbstractRequest
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'DCSALE'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'DCSALE'
12
12
 
13
13
  attr_element_mapping attribute: :merchant_supplied_id, element: 'Id'
14
14
  attr_element_mapping attribute: :client_id, element: 'ClientId'
@@ -8,10 +8,10 @@ module ClientForPoslynx
8
8
 
9
9
  class PinPadDisplayMessage < AbstractRequest
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'PPDISPLAY'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'PPDISPLAY'
12
12
  attr_element_mapping attribute: :line_count, element: 'Lines'
13
- attr_element_mapping attribute: :text_lines, element: 'Text', type: :array
14
- attr_element_mapping attribute: :button_labels, element: 'Buttons', type: :array
13
+ attr_element_mapping attribute: :text_lines, element: 'Text', multi_text: true
14
+ attr_element_mapping attribute: :button_labels, element: 'Buttons', multi_text: true
15
15
 
16
16
  end
17
17
 
@@ -8,11 +8,11 @@ module ClientForPoslynx
8
8
 
9
9
  class PinPadDisplaySpecifiedForm < AbstractRequest
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'PPSPECIFIEDFORM'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'PPSPECIFIEDFORM'
12
12
 
13
13
  attr_element_mapping attribute: :form_name, element: 'FormName'
14
- attr_element_mapping attribute: :text_values, element: 'Text', type: :array
15
- attr_element_mapping attribute: :button_labels, element: 'Buttons', type: :array
14
+ attr_element_mapping attribute: :text_values, element: 'Text', multi_text: true
15
+ attr_element_mapping attribute: :button_labels, element: 'Buttons', multi_text: true
16
16
 
17
17
  end
18
18
 
@@ -8,7 +8,7 @@ module ClientForPoslynx
8
8
 
9
9
  class PinPadInitialize < AbstractRequest
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'PPINIT'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'PPINIT'
12
12
  attr_element_mapping attribute: :idle_prompt, element: 'IdlePrompt'
13
13
 
14
14
  end
@@ -8,7 +8,7 @@ module ClientForPoslynx
8
8
 
9
9
  class CreditCardSale < AbstractResponse
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'CCSALE'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'CCSALE'
12
12
 
13
13
  attr_element_mapping attribute: :processor_authorization, element: 'Authorization'
14
14
  attr_element_mapping attribute: :record_number, element: 'RecNum'
@@ -8,7 +8,7 @@ module ClientForPoslynx
8
8
 
9
9
  class DebitCardSale < AbstractResponse
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'DCSALE'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'DCSALE'
12
12
 
13
13
  attr_element_mapping attribute: :processor_authorization, element: 'Authorization'
14
14
  attr_element_mapping attribute: :record_number, element: 'RecNum'
@@ -8,7 +8,7 @@ module ClientForPoslynx
8
8
 
9
9
  class PinPadDisplayMessage < AbstractResponse
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'PPDISPLAY'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'PPDISPLAY'
12
12
  attr_element_mapping attribute: :button_response, element: 'Response'
13
13
 
14
14
  end
@@ -8,7 +8,7 @@ module ClientForPoslynx
8
8
 
9
9
  class PinPadDisplaySpecifiedForm < AbstractResponse
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'PPSPECIFIEDFORM'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'PPSPECIFIEDFORM'
12
12
  attr_element_mapping attribute: :button_response, element: 'Response'
13
13
  attr_element_mapping attribute: :signature_data, element: 'Signature'
14
14
 
@@ -8,7 +8,7 @@ module ClientForPoslynx
8
8
 
9
9
  class PinPadInitialize < AbstractResponse
10
10
 
11
- defining_element_value attribute: :command, element: 'Command', value: 'PPINIT'
11
+ defining_property_value attribute: :command, element: 'Command', value: 'PPINIT'
12
12
 
13
13
  end
14
14
 
@@ -7,18 +7,42 @@ module ClientForPoslynx
7
7
 
8
8
  class XmlDocument
9
9
 
10
- attr_reader :source_xml
11
-
12
- def initialize( source_xml )
13
- @source_xml = source_xml
14
- @nokogiri_doc = Nokogiri::XML::Document.parse(
15
- source_xml,
16
- nil, nil,
17
- Nokogiri::XML::ParseOptions::DEFAULT_XML & ~Nokogiri::XML::ParseOptions::RECOVER
10
+ class << self
11
+ private :new
12
+
13
+ def with_root_element_name(name)
14
+ nokogiri_doc = Nokogiri::XML::Document.new
15
+ nokogiri_doc.root = nokogiri_doc.create_element( name )
16
+ new(nokogiri_doc)
17
+ end
18
+
19
+ def from_xml(source_xml)
20
+ nokogiri_doc = Nokogiri::XML::Document.parse(
21
+ source_xml,
22
+ nil, nil,
23
+ Nokogiri::XML::ParseOptions::DEFAULT_XML & ~Nokogiri::XML::ParseOptions::RECOVER
24
+ )
25
+ new(nokogiri_doc)
26
+ rescue Nokogiri::XML::SyntaxError => e
27
+ raise InvalidXmlError
28
+ end
29
+
30
+ end
31
+
32
+ def initialize(nokogiri_doc)
33
+ @nokogiri_doc = nokogiri_doc
34
+ end
35
+
36
+ def verify_root_element_name(expected_name)
37
+ unless root_name == expected_name
38
+ raise InvalidXmlContentError, "#{expected_name} root element not found"
39
+ end
40
+ end
41
+
42
+ def serialize
43
+ nokogiri_doc.serialize(
44
+ :save_with => Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
18
45
  )
19
- rescue Nokogiri::XML::SyntaxError => e
20
- p e
21
- raise InvalidXmlError
22
46
  end
23
47
 
24
48
  def root_name
@@ -29,6 +53,19 @@ module ClientForPoslynx
29
53
  @property_element_contents ||= hash_from_element( root )
30
54
  end
31
55
 
56
+ def add_property_content(element_name, content)
57
+ element = nokogiri_doc.create_element( element_name )
58
+ if Hash === content
59
+ content.each do |element_name, text|
60
+ child_element = nokogiri_doc.create_element( element_name, nil, nil, text )
61
+ element.add_child child_element
62
+ end
63
+ else
64
+ element.content = content.to_s
65
+ end
66
+ root.add_child element
67
+ end
68
+
32
69
  private
33
70
 
34
71
  attr_reader :nokogiri_doc
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
2
 
3
3
  module ClientForPoslynx
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -0,0 +1,52 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ClientForPoslynx::Data::AbstractData::AttributeElementMapping do
6
+
7
+ it "Fails creation without :attribute option" do
8
+ expect{
9
+ described_class.new element: 'Foo'
10
+ }.to raise_exception( ArgumentError )
11
+ end
12
+
13
+ it "Fails creation without :element option" do
14
+ expect{
15
+ described_class.new attribute: :foo
16
+ }.to raise_exception( ArgumentError )
17
+ end
18
+
19
+ it "Creates a text mapping instance with minimum attriubtes" do
20
+ actual = described_class.new(
21
+ attribute: :foo, element: 'Foo'
22
+ )
23
+ expect( actual ).to be_text_mapping
24
+ end
25
+
26
+ it "Creates a multi-text mapping instance with multi_text attribute" do
27
+ actual = described_class.new(
28
+ attribute: :foo, element: 'Foo', multi_text: true
29
+ )
30
+ expect( actual ).to be_multi_text_mapping
31
+ end
32
+
33
+ it "Creates a numbered_lines mapping instance with numbered_lines attribute" do
34
+ actual = described_class.new(
35
+ attribute: :foo, element: 'Foo', numbered_lines: 'the-template'
36
+ )
37
+ expect( actual ).to be_numbered_lines_mapping
38
+ end
39
+
40
+ it "Fails creation with unexpected attribute" do
41
+ expect{
42
+ described_class.new attribute: :foo, element: 'Foo', bar: true
43
+ }.to raise_exception( ArgumentError )
44
+ end
45
+
46
+ it "fails creation with both nulti-text and numbered-lines options" do
47
+ expect{
48
+ described_class.new attribute: :foo, element: 'Foo', multi_text: true, numbered_lines: 'x'
49
+ }.to raise_exception( ArgumentError )
50
+ end
51
+
52
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: client_for_poslynx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Jorgensen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-31 00:00:00.000000000 Z
11
+ date: 2014-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -89,6 +89,8 @@ files:
89
89
  - lib/client_for_poslynx.rb
90
90
  - lib/client_for_poslynx/data.rb
91
91
  - lib/client_for_poslynx/data/abstract_data.rb
92
+ - lib/client_for_poslynx/data/abstract_data/attribute_element_mapping.rb
93
+ - lib/client_for_poslynx/data/abstract_data/defining_property_mapping.rb
92
94
  - lib/client_for_poslynx/data/properties_xml_parser.rb
93
95
  - lib/client_for_poslynx/data/requests.rb
94
96
  - lib/client_for_poslynx/data/requests/abstract_request.rb
@@ -127,6 +129,7 @@ files:
127
129
  - lib/client_for_poslynx/message_handling/stream_data_writer.rb
128
130
  - lib/client_for_poslynx/message_handling/xml_extractor.rb
129
131
  - lib/client_for_poslynx/version.rb
132
+ - spec/client_for_poslynx/data/abstract_data/attribute_element_mapping_spec.rb
130
133
  - spec/client_for_poslynx/data/abstract_data_spec.rb
131
134
  - spec/client_for_poslynx/data/requests/abstract_request_spec.rb
132
135
  - spec/client_for_poslynx/data/requests/can_visit_spec.rb
@@ -172,6 +175,7 @@ signing_key:
172
175
  specification_version: 4
173
176
  summary: A TCP client for Precidia's POSLynx™ devices
174
177
  test_files:
178
+ - spec/client_for_poslynx/data/abstract_data/attribute_element_mapping_spec.rb
175
179
  - spec/client_for_poslynx/data/abstract_data_spec.rb
176
180
  - spec/client_for_poslynx/data/requests/abstract_request_spec.rb
177
181
  - spec/client_for_poslynx/data/requests/can_visit_spec.rb