sapoci 0.1.4

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.
@@ -0,0 +1,21 @@
1
+ # 0.1.4, release 2011-07-14
2
+
3
+ * Add various before_type_cast methods
4
+
5
+ # 0.1.3, release 2011-07-14
6
+
7
+ * Ignore whitespace on numeric fields
8
+
9
+ # 0.1.2, release 2011-07-05
10
+
11
+ * Use Nokogiri 1.5.0
12
+
13
+ # 0.1.1, release 2011-04-30
14
+
15
+ * Removed version from sources and put it into gemspec only
16
+
17
+ # 0.1.0, released 2011-04-29
18
+
19
+ * Added a gemspec
20
+ * Initial release on GitHub
21
+
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2007-2011 Oliver Eilhard
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,14 @@
1
+ # SAP-OCI
2
+
3
+ ## Description
4
+
5
+ Ruby library and Rails plugin for punchout via SAP OCI protocol.
6
+
7
+ ## Installation
8
+
9
+ $ gem install sapoci
10
+
11
+ ## License
12
+
13
+ Released under the MIT License. See the LICENSE file for further
14
+ details.
@@ -0,0 +1,16 @@
1
+ # Copyright (C) 2010 Oliver Eilhard
2
+ #
3
+ # This SAP OCI library is freely distributable under
4
+ # the terms of an MIT-style license.
5
+ # See COPYING or http://www.opensource.org/licenses/mit-license.php.
6
+
7
+ # This library is for parsing and emitting shopping cart data and
8
+ # behavior in SAP OCI style.
9
+
10
+ module SAPOCI
11
+ VERSION_40 = "4.0"
12
+
13
+ autoload :CoreExt, 'sapoci/core_ext.rb'
14
+ autoload :Document, 'sapoci/document.rb'
15
+ autoload :Item, 'sapoci/item.rb'
16
+ end
@@ -0,0 +1,2 @@
1
+ require 'sapoci/core_ext/try.rb'
2
+ require 'sapoci/core_ext/blank.rb'
@@ -0,0 +1,59 @@
1
+ class Object #:nodoc:
2
+ unless respond_to?(:blank?)
3
+ def blank?
4
+ respond_to?(:empty?) ? empty? : !self
5
+ end
6
+ end
7
+ end
8
+
9
+ class NilClass #:nodoc:
10
+ unless respond_to?(:blank?)
11
+ def blank?
12
+ true
13
+ end
14
+ end
15
+ end
16
+
17
+ class FalseClass #:nodoc:
18
+ unless respond_to?(:blank?)
19
+ def blank?
20
+ true
21
+ end
22
+ end
23
+ end
24
+
25
+ class TrueClass #:nodoc:
26
+ unless respond_to?(:blank?)
27
+ def blank?
28
+ false
29
+ end
30
+ end
31
+ end
32
+
33
+ class Array #:nodoc:
34
+ unless respond_to?(:blank?)
35
+ alias_method :blank?, :empty?
36
+ end
37
+ end
38
+
39
+ class Hash #:nodoc:
40
+ unless respond_to?(:blank?)
41
+ alias_method :blank?, :empty?
42
+ end
43
+ end
44
+
45
+ class String #:nodoc:
46
+ unless respond_to?(:blank?)
47
+ def blank?
48
+ self !~ /\S/
49
+ end
50
+ end
51
+ end
52
+
53
+ class Numeric #:nodoc:
54
+ unless respond_to?(:blank?)
55
+ def blank?
56
+ false
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,11 @@
1
+ class Object
2
+ alias_method(:try, :__send__) unless respond_to?(:try)
3
+ end
4
+
5
+ class NilClass
6
+ unless respond_to?(:try)
7
+ def try(*args)
8
+ nil
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems' unless RUBY_VERSION >= '1.9'
4
+ require 'nokogiri'
5
+ require 'sapoci/core_ext'
6
+
7
+ module SAPOCI
8
+ # SAPOCI::Document is for parsing and emitting SAP OCI compliant
9
+ # data.
10
+ #
11
+ # Open a +Document+ by feeding it a string:
12
+ #
13
+ # doc = SAPOCI::Document.from_html("<html>...</html>")
14
+ #
15
+ # Open a +Document+ by parsing a Rails-/Rack compatible +Hash+:
16
+ #
17
+ # doc = SAPOCI::Document.from_params({ "NEW_ITEM-DESCRIPTION"=>{"1"=>"Standard Visitenkarte deutsch 200 St."} })
18
+ #
19
+ class Document
20
+ def initialize(items)
21
+ @items = items
22
+ end
23
+
24
+ # Create a new document from a HTML string.
25
+ def self.from_html(html)
26
+ html_doc = Nokogiri::HTML(html)
27
+ doc = Document.new(parse_html(html_doc))
28
+ yield doc if block_given?
29
+ doc
30
+ end
31
+
32
+ # Create a new document from a Rails-/Rack-compatible
33
+ # params hash.
34
+ def self.from_params(params)
35
+ doc = Document.new(parse_params(params))
36
+ yield doc if block_given?
37
+ doc
38
+ end
39
+
40
+ # All +Item+ instances.
41
+ attr_reader :items
42
+
43
+ # Returns all +items+ as HTML hidden field tags.
44
+ def to_html(options = {})
45
+ html = []
46
+ self.items.each do |item|
47
+ html << item.to_html(options)
48
+ end
49
+ html.join
50
+ end
51
+
52
+ private
53
+
54
+ # Parses a Nokogiri HTML document and returns
55
+ # +Item+ instances in an array.
56
+ def self.parse_html(doc)
57
+ items = {}
58
+ doc.xpath("//input[starts-with(@name, 'NEW_ITEM-')]").each do |item_node|
59
+ name = item_node.attribute("name")
60
+ if /NEW_ITEM-(\w+)\[(\d+)\]/.match(name)
61
+ property = $1
62
+ index = $2.to_i - 1
63
+ value = item_node.attribute("value").value
64
+ items[index] = Item.new(index) unless items[index]
65
+ items[index].send((property+'=').downcase.to_sym, value)
66
+ end
67
+ end
68
+ items.inject([]) { |memo, (key, value)| memo << value }.sort_by(&:index)
69
+ end
70
+
71
+ # Parses a Rails-/Rack-compatible params hash and returns
72
+ # +Item+ instances in an array.
73
+ def self.parse_params(params)
74
+ items = {}
75
+ (params || {}).each do |oci_name, oci_values|
76
+ if oci_name =~ /NEW_ITEM-/
77
+ # Parse anything but NEW_ITEM-LONGTEXT (which is special, see below)
78
+ oci_values.each do |index, value|
79
+ index = index.to_i - 1 rescue next
80
+ property = /NEW_ITEM-(\w+)/.match(oci_name)[1]
81
+ next if property =~ /LONGTEXT/
82
+ method = (property+'=').downcase.to_sym
83
+ items[index] = Item.new(index) unless items[index]
84
+ items[index].send(method, value) if items[index].respond_to?(method)
85
+ end if oci_values && oci_values.respond_to?(:each)
86
+
87
+ # LONGTEXT is a special case because it doesn't follow the conventions
88
+ # Format is:
89
+ # NEW_ITEM-LONTEXT_n:132[]
90
+ # But shops use other (invalid) formats as well (and we're ready to accept them):
91
+ # NEW_ITEM-LONGTEXT_n:132[n]
92
+ # NEW_ITEM_LONGTEXT_n:132
93
+ #
94
+ if /NEW_ITEM-LONGTEXT_(\d+):132/.match(oci_name)
95
+ index = $1.to_i - 1
96
+ if oci_values.is_a?(Array)
97
+ # NEW_ITEM-LONGTEXT_1:132[]
98
+ items[index] = Item.new(index) unless items[index]
99
+ items[index].longtext = oci_values.first
100
+ elsif oci_values.is_a?(String)
101
+ # NEW_ITEM-LONGTEXT_1:132 <= invalid but parsed!
102
+ items[index] = Item.new(index) unless items[index]
103
+ items[index].longtext = oci_values
104
+ elsif oci_values.is_a?(Hash)
105
+ # NEW_ITEM-LONGTEXT_1:132[1] <= invalid but parsed!
106
+ items[index] = Item.new(index) unless items[index]
107
+ items[index].longtext = oci_values.first.last
108
+ end
109
+ end if oci_values
110
+ end # oci_name =~ /NEW_ITEM-/
111
+ end
112
+ items.inject([]) { |memo, (key, value)| memo << value }.sort_by(&:index)
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems' unless RUBY_VERSION >= '1.9'
4
+ require 'nokogiri'
5
+ require 'sapoci/core_ext'
6
+ require 'bigdecimal'
7
+
8
+ module SAPOCI
9
+ class Item
10
+
11
+ attr_reader :index
12
+ attr_accessor :description
13
+ attr_accessor :matnr
14
+ attr_accessor :quantity
15
+ attr_accessor :unit
16
+ attr_accessor :price
17
+ attr_accessor :currency
18
+ attr_accessor :priceunit
19
+ attr_accessor :leadtime
20
+ attr_accessor :longtext
21
+ attr_accessor :vendor
22
+ attr_accessor :vendormat
23
+ attr_accessor :manufactcode
24
+ attr_accessor :manufactmat
25
+ attr_accessor :matgroup
26
+ attr_accessor :service
27
+ attr_accessor :contract
28
+ attr_accessor :contract_item
29
+ attr_accessor :ext_quote_id
30
+ attr_accessor :ext_quote_item
31
+ attr_accessor :ext_product_id
32
+ attr_accessor :attachment
33
+ attr_accessor :attachment_title
34
+ attr_accessor :attachment_purpose
35
+ attr_accessor :ext_schema_type
36
+ attr_accessor :ext_category_id
37
+ attr_accessor :ext_category
38
+ attr_accessor :sld_sys_name
39
+ attr_accessor :cust_field1
40
+ attr_accessor :cust_field2
41
+ attr_accessor :cust_field3
42
+ attr_accessor :cust_field4
43
+ attr_accessor :cust_field5
44
+
45
+ # Initializes the item.
46
+ def initialize(index)
47
+ @index = index
48
+ end
49
+
50
+ def quantity
51
+ BigDecimal.new("0#{@quantity.to_s.strip}")
52
+ end
53
+
54
+ def quantity_before_type_cast
55
+ @quantity
56
+ end
57
+
58
+ def price
59
+ BigDecimal.new("0#{@price.to_s.strip}")
60
+ end
61
+
62
+ def price_before_type_cast
63
+ @price
64
+ end
65
+
66
+ def priceunit
67
+ BigDecimal.new("0#{@priceunit.to_s.strip}")
68
+ end
69
+
70
+ def priceunit_before_type_cast
71
+ @priceunit
72
+ end
73
+
74
+ def leadtime
75
+ @leadtime.to_i if @leadtime
76
+ end
77
+
78
+ def leadtime_before_type_cast
79
+ @leadtime
80
+ end
81
+
82
+ def service?
83
+ self.service == "X"
84
+ end
85
+
86
+ # Returns the item properties as HTML hidden field tags.
87
+ def to_html(options = {})
88
+ html = []
89
+ html << hidden_field_tag("DESCRIPTION", self.description) unless self.description.blank?
90
+ html << hidden_field_tag("MATNR", self.matnr) unless self.matnr.blank?
91
+ html << hidden_field_tag("QUANTITY", "%015.3f" % self.quantity)
92
+ html << hidden_field_tag("UNIT", self.unit) unless self.unit.blank?
93
+ html << hidden_field_tag("PRICE", "%015.3f" % self.price)
94
+ html << hidden_field_tag("CURRENCY", self.currency) unless self.currency.blank?
95
+ html << hidden_field_tag("PRICEUNIT", self.priceunit.to_i) if self.priceunit.to_i > 0
96
+ html << hidden_field_tag("LEADTIME", "%05d" % self.leadtime) if self.leadtime.to_i > 0
97
+ html << hidden_field_tag("VENDOR", self.vendor) unless self.vendor.blank?
98
+ html << hidden_field_tag("VENDORMAT", self.vendormat) unless self.vendormat.blank?
99
+ html << hidden_field_tag("MANUFACTCODE", self.manufactcode) unless self.manufactcode.blank?
100
+ html << hidden_field_tag("MANUFACTMAT", self.manufactmat) unless self.manufactmat.blank?
101
+ html << hidden_field_tag("MATGROUP", self.matgroup) unless self.matgroup.blank?
102
+ html << hidden_field_tag("SERVICE", "X") if self.service?
103
+ html << hidden_field_tag("CONTRACT", self.contract) unless self.contract.blank?
104
+ html << hidden_field_tag("CONTRACT_ITEM", self.contract_item) unless self.contract_item.blank?
105
+ html << hidden_field_tag("EXT_QUOTE_ID", self.ext_quote_id) unless self.ext_quote_id.blank?
106
+ html << hidden_field_tag("EXT_QUOTE_ITEM", self.ext_quote_item) unless self.ext_quote_item.blank?
107
+ html << hidden_field_tag("EXT_PRODUCT_ID", self.ext_product_id) unless self.ext_product_id.blank?
108
+ html << hidden_field_tag("ATTACHMENT", self.attachment) unless self.attachment.blank?
109
+ html << hidden_field_tag("ATTACHMENT_TITLE", self.attachment_title) unless self.attachment_title.blank?
110
+ html << hidden_field_tag("ATTACHMENT_PURPOSE", self.attachment_purpose) unless self.attachment_purpose.blank?
111
+ html << hidden_field_tag("EXT_SCHEMA_TYPE", self.ext_schema_type) unless self.ext_schema_type.blank?
112
+ html << hidden_field_tag("EXT_CATEGORY_ID", self.ext_category_id) unless self.ext_category_id.blank?
113
+ html << hidden_field_tag("EXT_CATEGORY", self.ext_category) unless self.ext_category.blank?
114
+ html << hidden_field_tag("SLD_SYS_NAME", self.sld_sys_name) unless self.sld_sys_name.blank?
115
+ html << hidden_field_tag("CUST_FIELD1", self.cust_field1) unless self.cust_field1.blank?
116
+ html << hidden_field_tag("CUST_FIELD2", self.cust_field2) unless self.cust_field2.blank?
117
+ html << hidden_field_tag("CUST_FIELD3", self.cust_field3) unless self.cust_field3.blank?
118
+ html << hidden_field_tag("CUST_FIELD4", self.cust_field4) unless self.cust_field4.blank?
119
+ html << hidden_field_tag("CUST_FIELD5", self.cust_field5) unless self.cust_field5.blank?
120
+ html << "<input type=\"hidden\" name=\"NEW_ITEM-LONGTEXT_#{index + 1}:132[]\" value=\"#{escape_html(self.longtext)}\" />" unless self.longtext.blank?
121
+ html.join
122
+ end
123
+
124
+ private
125
+
126
+ def hidden_field_tag(name, value, options = {})
127
+ "<input type=\"hidden\" name=\"NEW_ITEM-#{name}[#{index + 1}]\" value=\"#{escape_html(value)}\" />"
128
+ end
129
+
130
+ ESCAPE_HTML = { "&" => "&amp;", "<" => "&lt;", ">" => "&gt;", "'" => "&#39;", '"' => "&quot;", }
131
+ ESCAPE_HTML_PATTERN = Regexp.union(ESCAPE_HTML.keys)
132
+
133
+ # Shamelessly borrowed from Rack::Utils.escape_html(s)
134
+ def escape_html(s)
135
+ s.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
136
+ end
137
+
138
+ end
139
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sapoci
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Oliver Eilhard
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-18 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &70261606168780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70261606168780
25
+ - !ruby/object:Gem::Dependency
26
+ name: rdoc
27
+ requirement: &70261606168260 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.5'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70261606168260
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70261606167780 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.2
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70261606167780
47
+ - !ruby/object:Gem::Dependency
48
+ name: nokogiri
49
+ requirement: &70261606166980 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.5.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70261606166980
58
+ description: Ruby library and Rails plugin for punchout via SAP OCI protocol.
59
+ email:
60
+ - oliver.eilhard@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files:
64
+ - CHANGELOG.md
65
+ - LICENSE
66
+ - README.md
67
+ files:
68
+ - lib/sapoci.rb
69
+ - lib/sapoci/core_ext.rb
70
+ - lib/sapoci/core_ext/blank.rb
71
+ - lib/sapoci/core_ext/try.rb
72
+ - lib/sapoci/document.rb
73
+ - lib/sapoci/item.rb
74
+ - CHANGELOG.md
75
+ - LICENSE
76
+ - README.md
77
+ homepage: http://github.com/meplato/sapoci
78
+ licenses: []
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --charset=UTF-8
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: 1.3.6
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 1.8.7
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Ruby library and Rails plugin for punchout via SAP OCI protocol.
102
+ test_files: []