client_for_poslynx 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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