burlap 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +38 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +2 -0
  5. data/.yardopts +1 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +21 -0
  8. data/README.md +16 -0
  9. data/Rakefile +31 -0
  10. data/burlap.gemspec +32 -0
  11. data/lib/active_support/ordered_hash.rb +179 -0
  12. data/lib/burlap/array.rb +18 -0
  13. data/lib/burlap/base_tag.rb +105 -0
  14. data/lib/burlap/call.rb +38 -0
  15. data/lib/burlap/core_ext/array.rb +7 -0
  16. data/lib/burlap/core_ext/boolean.rb +11 -0
  17. data/lib/burlap/core_ext/float.rb +5 -0
  18. data/lib/burlap/core_ext/hash.rb +5 -0
  19. data/lib/burlap/core_ext/integer.rb +10 -0
  20. data/lib/burlap/core_ext/nil.rb +5 -0
  21. data/lib/burlap/core_ext/object.rb +13 -0
  22. data/lib/burlap/core_ext/string.rb +5 -0
  23. data/lib/burlap/core_ext/symbol.rb +6 -0
  24. data/lib/burlap/core_ext/time.rb +5 -0
  25. data/lib/burlap/core_ext.rb +10 -0
  26. data/lib/burlap/default_resolver.rb +100 -0
  27. data/lib/burlap/error.rb +3 -0
  28. data/lib/burlap/fault.rb +6 -0
  29. data/lib/burlap/hash.rb +72 -0
  30. data/lib/burlap/listener.rb +34 -0
  31. data/lib/burlap/node.rb +48 -0
  32. data/lib/burlap/version.rb +3 -0
  33. data/lib/burlap.rb +47 -0
  34. data/lib/core_ext/time_burlap_iso8601.rb +32 -0
  35. data/spec/burlap/array_spec.rb +28 -0
  36. data/spec/burlap/call_spec.rb +126 -0
  37. data/spec/burlap/core_ext/array_spec.rb +123 -0
  38. data/spec/burlap/core_ext/class_spec.rb +24 -0
  39. data/spec/burlap/core_ext/false_class_spec.rb +17 -0
  40. data/spec/burlap/core_ext/float_spec.rb +15 -0
  41. data/spec/burlap/core_ext/hash_spec.rb +15 -0
  42. data/spec/burlap/core_ext/integer_spec.rb +28 -0
  43. data/spec/burlap/core_ext/nil_class_spec.rb +15 -0
  44. data/spec/burlap/core_ext/object_spec.rb +62 -0
  45. data/spec/burlap/core_ext/string_spec.rb +27 -0
  46. data/spec/burlap/core_ext/symbol_spec.rb +15 -0
  47. data/spec/burlap/core_ext/time_spec.rb +23 -0
  48. data/spec/burlap/core_ext/true_class_spec.rb +17 -0
  49. data/spec/burlap/default_resolver_spec.rb +140 -0
  50. data/spec/burlap/error_spec.rb +7 -0
  51. data/spec/burlap/hash_spec.rb +234 -0
  52. data/spec/burlap/listener_spec.rb +31 -0
  53. data/spec/burlap/node_spec.rb +39 -0
  54. data/spec/burlap_spec.rb +55 -0
  55. data/spec/data/no_such_method.burlap +1 -0
  56. data/spec/data/record_not_found.burlap +1 -0
  57. data/spec/spec_helper.rb +13 -0
  58. metadata +224 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a943c13d8d1a707bb5cd7aa90b1044294f3ac83e92bbc9dc47013bc665646015
4
+ data.tar.gz: 148192348442c2b25471c582c35800f38f37bed6275e54db5d29f40dfade6659
5
+ SHA512:
6
+ metadata.gz: 887990e582c68cc1603786307e76cc02f75e9770d01404e21e84f42ed4584c578614e704874f33504a0b33ae5c97287aa57b109e4b2e913d311e299a8888cd13
7
+ data.tar.gz: d00650665f60de24108f908bb804a15d835bb61957a473ae15f6e63d6c842c23e675be8a3362dac1c9583e61f8865b851db27c8b61eeb04bb298cfce91ee2c50
@@ -0,0 +1,38 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ "master" ]
13
+ pull_request:
14
+ branches: [ "master" ]
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ test:
21
+
22
+ runs-on: ubuntu-latest
23
+ strategy:
24
+ matrix:
25
+ ruby-version: ["2.3", "2.4", "2.5", "2.6", "2.7", "3.0", "3.1"]
26
+
27
+ steps:
28
+ - uses: actions/checkout@v3
29
+ - name: Set up Ruby
30
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
31
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
32
+ # uses: ruby/setup-ruby@v1
33
+ uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
34
+ with:
35
+ ruby-version: ${{ matrix.ruby-version }}
36
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
37
+ - name: Run tests
38
+ run: bundle exec rspec
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ tmp/*
5
+ log/*
6
+ doc/*
7
+ .yardoc
8
+ Gemfile.lock
9
+ vendor
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=progress
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup=markdown
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in brappa.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2010 Brightbox Systems Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # Burlap
2
+
3
+ This gem handles parsing and generating [Burlap][] XML.
4
+
5
+
6
+ ## Installation
7
+
8
+ gem install burlap
9
+
10
+ or from the git repo
11
+
12
+ rake install
13
+
14
+ ## Development
15
+
16
+ Clone the git repo
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ begin
5
+ require "rspec/core/rake_task"
6
+ require "rspec/core/version"
7
+
8
+ desc "Run all examples"
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ t.rspec_opts = %w(--color)
11
+ end
12
+ rescue LoadError
13
+ # rspec not loaded, tasks not available
14
+ desc "[RSpec failed to load] Run all examples"
15
+ task :spec do
16
+ fail "RSpec failed to load, this task can't be run"
17
+ end
18
+ end
19
+
20
+ desc "Alias for spec"
21
+ task :test => :spec
22
+
23
+ begin
24
+ require "yard"
25
+
26
+ YARD::Rake::YardocTask.new :doc do |yard|
27
+ yard.files = Dir.glob("lib/**/*.rb")
28
+ end
29
+ rescue LoadError
30
+ puts "failed to load yard"
31
+ end
data/burlap.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "burlap/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "burlap"
7
+ s.version = Burlap::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Caius Durling", "Paul Thornthwaite", "John Leach"]
10
+ s.email = ["hello@brightbox.com"]
11
+ s.homepage = "https://github.com/brightbox/burlap"
12
+ s.summary = %q{Wrapper for burlap APIs}
13
+ s.description = %q{Translates responses from Burlap APIs to ruby, and generates requests to send back.}
14
+ s.license = "MIT"
15
+ s.metadata['rubygems_mfa_required'] = "true"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.required_ruby_version = "> 2.3"
23
+
24
+ s.add_dependency "nokogiri", ">= 1.4.4"
25
+ s.add_dependency "builder", ">= 2.0"
26
+
27
+ s.add_development_dependency "rspec", "~> 3.0"
28
+ s.add_development_dependency "activesupport", ">= 2.3.4"
29
+ s.add_development_dependency "timecop", "= 0.3.5"
30
+ s.add_development_dependency "rake"
31
+ s.add_development_dependency "yard"
32
+ end
@@ -0,0 +1,179 @@
1
+ require 'yaml'
2
+
3
+ YAML.add_builtin_type("omap") do |type, val|
4
+ ActiveSupport::OrderedHash[val.map(&:to_a).map(&:first)]
5
+ end
6
+
7
+ # OrderedHash is namespaced to prevent conflicts with other implementations
8
+ module ActiveSupport #:nodoc:
9
+ class OrderedHash < ::Hash #:nodoc:
10
+ def to_yaml_type
11
+ "!tag:yaml.org,2002:omap"
12
+ end
13
+
14
+ def to_yaml(opts = {})
15
+ YAML.quick_emit(self, opts) do |out|
16
+ out.seq(taguri, to_yaml_style) do |seq|
17
+ each do |k, v|
18
+ seq.add(k => v)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ # Hash is ordered in Ruby 1.9!
25
+ if RUBY_VERSION < '1.9'
26
+
27
+ # In MRI the Hash class is core and written in C. In particular, methods are
28
+ # programmed with explicit C function calls and polymorphism is not honored.
29
+ #
30
+ # For example, []= is crucial in this implementation to maintain the @keys
31
+ # array but hash.c invokes rb_hash_aset() originally. This prevents method
32
+ # reuse through inheritance and forces us to reimplement stuff.
33
+ #
34
+ # For instance, we cannot use the inherited #merge! because albeit the algorithm
35
+ # itself would work, our []= is not being called at all by the C code.
36
+
37
+ def initialize(*args, &block)
38
+ super
39
+ @keys = []
40
+ end
41
+
42
+ def self.[](*args)
43
+ ordered_hash = new
44
+
45
+ if (args.length == 1 && args.first.is_a?(Array))
46
+ args.first.each do |key_value_pair|
47
+ next unless (key_value_pair.is_a?(Array))
48
+ ordered_hash[key_value_pair[0]] = key_value_pair[1]
49
+ end
50
+
51
+ return ordered_hash
52
+ end
53
+
54
+ unless (args.size % 2 == 0)
55
+ raise ArgumentError.new("odd number of arguments for Hash")
56
+ end
57
+
58
+ args.each_with_index do |val, ind|
59
+ next if (ind % 2 != 0)
60
+ ordered_hash[val] = args[ind + 1]
61
+ end
62
+
63
+ ordered_hash
64
+ end
65
+
66
+ def initialize_copy(other)
67
+ super
68
+ # make a deep copy of keys
69
+ @keys = other.keys
70
+ end
71
+
72
+ def []=(key, value)
73
+ @keys << key if !has_key?(key)
74
+ super
75
+ end
76
+
77
+ def delete(key)
78
+ if has_key? key
79
+ index = @keys.index(key)
80
+ @keys.delete_at index
81
+ end
82
+ super
83
+ end
84
+
85
+ def delete_if
86
+ super
87
+ sync_keys!
88
+ self
89
+ end
90
+
91
+ def reject!
92
+ super
93
+ sync_keys!
94
+ self
95
+ end
96
+
97
+ def reject(&block)
98
+ dup.reject!(&block)
99
+ end
100
+
101
+ def keys
102
+ @keys.dup
103
+ end
104
+
105
+ def values
106
+ @keys.collect { |key| self[key] }
107
+ end
108
+
109
+ def to_hash
110
+ self
111
+ end
112
+
113
+ def to_a
114
+ @keys.map { |key| [ key, self[key] ] }
115
+ end
116
+
117
+ def each_key
118
+ @keys.each { |key| yield key }
119
+ end
120
+
121
+ def each_value
122
+ @keys.each { |key| yield self[key]}
123
+ end
124
+
125
+ def each
126
+ @keys.each {|key| yield [key, self[key]]}
127
+ end
128
+
129
+ alias_method :each_pair, :each
130
+
131
+ def clear
132
+ super
133
+ @keys.clear
134
+ self
135
+ end
136
+
137
+ def shift
138
+ k = @keys.first
139
+ v = delete(k)
140
+ [k, v]
141
+ end
142
+
143
+ def merge!(other_hash)
144
+ if block_given?
145
+ other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
146
+ else
147
+ other_hash.each { |k, v| self[k] = v }
148
+ end
149
+ self
150
+ end
151
+
152
+ alias_method :update, :merge!
153
+
154
+ def merge(other_hash, &block)
155
+ dup.merge!(other_hash, &block)
156
+ end
157
+
158
+ # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
159
+ def replace(other)
160
+ super
161
+ @keys = other.keys
162
+ self
163
+ end
164
+
165
+ def invert
166
+ OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
167
+ end
168
+
169
+ def inspect
170
+ "#<OrderedHash #{super}>"
171
+ end
172
+
173
+ private
174
+ def sync_keys!
175
+ @keys.delete_if {|k| !has_key?(k)}
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,18 @@
1
+ module Burlap
2
+ class Array < ::Array
3
+
4
+ def to_burlap
5
+ # <list><type>[string</type><length>1</length><string>Some</string></list>
6
+ list_content = [
7
+ Burlap::Node.new(:name => "type", :value => "").to_burlap,
8
+ Burlap::Node.new(:name => "length", :value => self.length.to_s).to_burlap
9
+ ]
10
+ list_content += self.map do |element|
11
+ element.to_burlap
12
+ end
13
+ list_content = list_content.join("")
14
+ Burlap::Node.new(:name => "list", :value => list_content).to_burlap
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,105 @@
1
+ module Burlap
2
+
3
+ class BaseTag
4
+ attr_accessor :name, :value, :children
5
+
6
+ def initialize params={}
7
+ params.each do |k,v|
8
+ meffod = :"#{k}="
9
+ send(meffod, v) if respond_to?(meffod)
10
+ end
11
+ end
12
+
13
+ def children
14
+ @children ||= []
15
+ end
16
+
17
+ def value
18
+ @value ||= ""
19
+ end
20
+
21
+ def parse_matched_pairs
22
+ # The children are matched pairs.
23
+ # We use an array here because ruby 1.8.x is _FUN_ to
24
+ # use ordered hashes with and doing it in an array is
25
+ # easier for now. Viva la 1.9!
26
+ values = []
27
+
28
+ self.children.each_slice(2) do |arr|
29
+ key = arr.first.to_ruby
30
+ value = if arr.last.name == "ref"
31
+ i = arr.last.value.to_i - 1
32
+ v = values[i]
33
+ v.last if v
34
+ else
35
+ arr.last.to_ruby
36
+ end
37
+
38
+ values << [key, value]
39
+ end
40
+
41
+ values
42
+ end
43
+
44
+ def to_ruby
45
+ Burlap.resolver.convert_to_native self
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+
52
+ __END__
53
+
54
+ # todo: introduce into resolver block for map
55
+ class Timestamp < Map
56
+ handle_mapping "java.sql.Timestamp"
57
+
58
+ def to_ruby
59
+ # This is already parsed as a Time object
60
+ contents["value"]
61
+ end
62
+ end
63
+
64
+ # todo: introduce into resolver block for map
65
+ require "bigdecimal"
66
+ class BigDecimal < Map
67
+ handle_mapping "java.math.BigDecimal"
68
+
69
+ def to_ruby
70
+ ::BigDecimal.new(contents["value"])
71
+ end
72
+ end
73
+ end
74
+
75
+ # todo: add a resolver block to parse this out
76
+ class Fault
77
+ attr_reader :code, :message, :detail_message, :stack_trace, :cause
78
+
79
+ def initialize opts={}
80
+ data = opts[:contents]
81
+
82
+ @message = data["message"]
83
+ @code = data["code"]
84
+ detail = data["detail"].contents
85
+ @detail_message = detail["detailMessage"]
86
+ @stack_trace = detail["stackTrace"]
87
+ @cause = detail["cause"]
88
+
89
+ @contents = nil
90
+ end
91
+ end
92
+
93
+ # todo: add a resolver block for this logic
94
+ class FaultTag < BaseTag
95
+ def to_ruby
96
+ dict = {}
97
+
98
+ children.each_slice(2) do |arr|
99
+ key, value = arr.map(&:to_ruby)
100
+ dict[key] = value
101
+ end
102
+
103
+ Fault.new(:contents => dict)
104
+ end
105
+ end
@@ -0,0 +1,38 @@
1
+ module Burlap
2
+ class Call
3
+ attr_accessor :headers, :method, :arguments
4
+
5
+ def initialize params={}
6
+ params.each do |key, value|
7
+ method = :"#{key}="
8
+ send(method, value) if respond_to?(method)
9
+ end
10
+
11
+ validate_attributes
12
+ end
13
+
14
+ def headers
15
+ @headers ||= {}
16
+ end
17
+
18
+ def arguments
19
+ @arguments ||= []
20
+ end
21
+
22
+ def to_burlap
23
+ # todo: handle headers
24
+ contents = [Burlap::Node.new(:name => "method", :value => method).to_burlap]
25
+ contents += arguments.map do |arg|
26
+ arg.to_burlap
27
+ end
28
+ Burlap::Node.new(:name => "burlap:call", :value => contents.join("")).to_burlap
29
+ end
30
+
31
+ protected
32
+
33
+ def validate_attributes
34
+ raise(ArgumentError, "method is required") unless self.method
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ class Array
2
+ def to_burlap
3
+ # We use the splat here so it creates an array with our elements,
4
+ # rather than an array containing an array of our elements
5
+ Burlap::Array[*to_a].to_burlap
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ class TrueClass
2
+ def to_burlap
3
+ Burlap::Node.new(:name => "boolean", :value => "1").to_burlap
4
+ end
5
+ end
6
+
7
+ class FalseClass
8
+ def to_burlap
9
+ Burlap::Node.new(:name => "boolean", :value => "0").to_burlap
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ class Float
2
+ def to_burlap
3
+ Burlap::Node.new(:name => "double", :value => self).to_burlap
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Hash
2
+ def to_burlap
3
+ Burlap::Hash[self].to_burlap
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ class Integer
2
+ def to_burlap
3
+ if between?(-2**31, 2**31-1)
4
+ Burlap::Node.new(:name => "int", :value => self.to_i).to_burlap
5
+ else
6
+ # <map><type>java.math.BigDecimal</type><string>value</string><string>0</string></map>
7
+ Burlap::Hash[{:value => self.to_i.to_s}, "java.math.BigDecimal"].to_burlap
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ class NilClass
2
+ def to_burlap
3
+ Burlap::Node.new(:name => "null", :value => "").to_burlap
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ class Object
2
+ def to_burlap
3
+ dict = {}
4
+
5
+ vars = instance_variables.map do |var|
6
+ key = var[/^@(.*)$/, 1]
7
+ value = instance_variable_get(var)
8
+ [key, value]
9
+ end.sort_by {|e| e.first }
10
+
11
+ Burlap::Hash[vars, self.class.to_s].to_burlap
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def to_burlap
3
+ Burlap::Node.new(:name => "string", :value => ERB::Util.html_escape(self)).to_burlap
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class Symbol
2
+ def to_burlap
3
+ # Return the same as if we were a string
4
+ self.to_s.to_burlap
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class Time
2
+ def to_burlap
3
+ Burlap::Node.new(:name => "date", :value => self.burlap_iso8601(3)).to_burlap
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require "burlap/core_ext/array"
2
+ require "burlap/core_ext/boolean"
3
+ require "burlap/core_ext/float"
4
+ require "burlap/core_ext/hash"
5
+ require "burlap/core_ext/integer"
6
+ require "burlap/core_ext/nil"
7
+ require "burlap/core_ext/object"
8
+ require "burlap/core_ext/string"
9
+ require "burlap/core_ext/symbol"
10
+ require "burlap/core_ext/time"