payshares-xdr 0.0.2

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 (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.travis.yml +14 -0
  4. data/.yardopts +7 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +5 -0
  7. data/LICENSE.txt +202 -0
  8. data/README.md +106 -0
  9. data/Rakefile +9 -0
  10. data/examples/enum.rb +30 -0
  11. data/examples/struct.rb +24 -0
  12. data/examples/union.rb +36 -0
  13. data/lib/xdr.rb +73 -0
  14. data/lib/xdr/array.rb +28 -0
  15. data/lib/xdr/bool.rb +24 -0
  16. data/lib/xdr/concerns/array_converter.rb +5 -0
  17. data/lib/xdr/concerns/converts_to_xdr.rb +67 -0
  18. data/lib/xdr/concerns/float_converter.rb +5 -0
  19. data/lib/xdr/concerns/integer_converter.rb +5 -0
  20. data/lib/xdr/concerns/reads_bytes.rb +8 -0
  21. data/lib/xdr/concerns/string_converter.rb +5 -0
  22. data/lib/xdr/double.rb +14 -0
  23. data/lib/xdr/dsl.rb +7 -0
  24. data/lib/xdr/dsl/enum.rb +24 -0
  25. data/lib/xdr/dsl/struct.rb +13 -0
  26. data/lib/xdr/dsl/union.rb +32 -0
  27. data/lib/xdr/enum.rb +48 -0
  28. data/lib/xdr/float.rb +14 -0
  29. data/lib/xdr/hyper.rb +14 -0
  30. data/lib/xdr/int.rb +14 -0
  31. data/lib/xdr/namespace.rb +26 -0
  32. data/lib/xdr/opaque.rb +28 -0
  33. data/lib/xdr/option.rb +30 -0
  34. data/lib/xdr/quadruple.rb +5 -0
  35. data/lib/xdr/rpc.rb +6 -0
  36. data/lib/xdr/rpc/record.rb +7 -0
  37. data/lib/xdr/rpc/record_reader.rb +16 -0
  38. data/lib/xdr/string.rb +36 -0
  39. data/lib/xdr/struct.rb +51 -0
  40. data/lib/xdr/struct_validator.rb +6 -0
  41. data/lib/xdr/union.rb +101 -0
  42. data/lib/xdr/union_validator.rb +7 -0
  43. data/lib/xdr/unsigned_hyper.rb +14 -0
  44. data/lib/xdr/unsigned_int.rb +14 -0
  45. data/lib/xdr/var_array.rb +38 -0
  46. data/lib/xdr/var_opaque.rb +36 -0
  47. data/lib/xdr/version.rb +3 -0
  48. data/lib/xdr/void.rb +14 -0
  49. data/payshares-xdr.gemspec +29 -0
  50. data/spec/lib/xdr/array_spec.rb +73 -0
  51. data/spec/lib/xdr/bool_spec.rb +43 -0
  52. data/spec/lib/xdr/concerns/converts_to_xdr_spec.rb +55 -0
  53. data/spec/lib/xdr/concerns/reads_bytes_spec.rb +31 -0
  54. data/spec/lib/xdr/double_spec.rb +38 -0
  55. data/spec/lib/xdr/dsl/enum_spec.rb +44 -0
  56. data/spec/lib/xdr/dsl/struct_spec.rb +29 -0
  57. data/spec/lib/xdr/dsl/union_spec.rb +22 -0
  58. data/spec/lib/xdr/enum_spec.rb +70 -0
  59. data/spec/lib/xdr/float_spec.rb +37 -0
  60. data/spec/lib/xdr/hyper_spec.rb +40 -0
  61. data/spec/lib/xdr/int_spec.rb +40 -0
  62. data/spec/lib/xdr/opaque_spec.rb +36 -0
  63. data/spec/lib/xdr/option_spec.rb +36 -0
  64. data/spec/lib/xdr/quadruple_spec.rb +14 -0
  65. data/spec/lib/xdr/rpc/record_reader_spec.rb +27 -0
  66. data/spec/lib/xdr/string_spec.rb +41 -0
  67. data/spec/lib/xdr/struct_spec.rb +101 -0
  68. data/spec/lib/xdr/union_spec.rb +248 -0
  69. data/spec/lib/xdr/unsigned_hyper_spec.rb +36 -0
  70. data/spec/lib/xdr/unsigned_int_spec.rb +36 -0
  71. data/spec/lib/xdr/var_array_spec.rb +71 -0
  72. data/spec/lib/xdr/var_opaque_spec.rb +43 -0
  73. data/spec/lib/xdr/void_spec.rb +46 -0
  74. data/spec/spec_helper.rb +15 -0
  75. data/spec/support/matchers/eq_bytes.rb +6 -0
  76. metadata +257 -0
@@ -0,0 +1,73 @@
1
+ require "xdr/version"
2
+ require "active_model"
3
+ require "active_support/concern"
4
+ require "active_support/dependencies/autoload"
5
+ require "active_support/core_ext/object/blank"
6
+ require "active_support/core_ext/object/try"
7
+ require "active_support/core_ext/module/attribute_accessors"
8
+ require "active_support/core_ext/class/attribute"
9
+ require "active_support/core_ext/hash/indifferent_access"
10
+ require "active_support/core_ext/string/inflections"
11
+ require "active_support/logger"
12
+ require "active_support/ordered_hash"
13
+ require "backports/2.1.0"
14
+
15
+ module XDR
16
+ extend ActiveSupport::Autoload
17
+
18
+ MAX_SIZE = 2**32 - 1
19
+
20
+ autoload :Namespace
21
+ autoload :RPC
22
+ autoload :DSL
23
+
24
+ # Compound Type
25
+ autoload :Struct
26
+ autoload :Union
27
+ autoload :Enum
28
+
29
+ # Primitive Types
30
+ autoload :Array
31
+ autoload :Option
32
+ autoload :Int
33
+ autoload :UnsignedInt
34
+ autoload :Hyper
35
+ autoload :UnsignedHyper
36
+ autoload :Float
37
+ autoload :Double
38
+ autoload :Quadruple
39
+ autoload :Bool
40
+ autoload :Opaque
41
+ autoload :VarOpaque
42
+ autoload :VarArray
43
+ autoload :String
44
+ autoload :Void
45
+
46
+ # Validators
47
+ autoload :StructValidator
48
+ autoload :UnionValidator
49
+
50
+ module Concerns
51
+ extend ActiveSupport::Autoload
52
+ autoload :ReadsBytes
53
+ autoload :ConvertsToXDR
54
+ autoload :IntegerConverter
55
+ autoload :FloatConverter
56
+ autoload :StringConverter
57
+ autoload :ArrayConverter
58
+ end
59
+
60
+ class Error < StandardError ; end
61
+ class ReadError < Error ; end
62
+ class EnumValueError < ReadError ; end
63
+ class EnumNameError < ReadError ; end
64
+ class WriteError < Error ; end
65
+
66
+ class InvalidSwitchError < Error ; end
67
+ class InvalidValueError < Error ; end
68
+ class ArmNotSetError < Error ; end
69
+
70
+ mattr_accessor :logger
71
+ self.logger = ActiveSupport::Logger.new(STDOUT)
72
+ self.logger.level = Logger::WARN
73
+ end
@@ -0,0 +1,28 @@
1
+ class XDR::Array
2
+ include XDR::Concerns::ConvertsToXDR
3
+ include XDR::Concerns::ArrayConverter
4
+
5
+ singleton_class.send(:alias_method, :[], :new)
6
+
7
+ def initialize(child_type, length)
8
+ @child_type = child_type
9
+ @length = length
10
+ end
11
+
12
+ def write(val, io)
13
+ raise XDR::WriteError, "val is not array" unless val.is_a?(Array)
14
+ raise XDR::WriteError, "array must be #{@length} long, was #{val.length}" if val.length != @length
15
+
16
+ @length.times do |i|
17
+ @child_type.write val[i], io
18
+ end
19
+ end
20
+
21
+ def read(io)
22
+ @length.times.map{ @child_type.read(io) }
23
+ end
24
+
25
+ def valid?(val)
26
+ super(val) && val.length == @length
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ module XDR::Bool
2
+ extend XDR::Concerns::ConvertsToXDR
3
+
4
+ def self.write(val, io)
5
+ case val
6
+ when true ; XDR::Int.write(1, io)
7
+ when false ; XDR::Int.write(0, io)
8
+ else ; raise XDR::WriteError, "Invalid bool value: #{val}"
9
+ end
10
+ end
11
+
12
+ def self.read(io)
13
+ val = XDR::Int.read(io)
14
+ case val
15
+ when 0 ; false
16
+ when 1 ; true
17
+ else ; raise XDR::ReadError, "Invalid bool value: #{val}"
18
+ end
19
+ end
20
+
21
+ def self.valid?(val)
22
+ val == true || val == false
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ module XDR::Concerns::ArrayConverter
2
+ def valid?(val)
3
+ val.is_a?(Array) && val.all?{|v| @child_type.valid?(v)}
4
+ end
5
+ end
@@ -0,0 +1,67 @@
1
+ module XDR::Concerns::ConvertsToXDR
2
+ include XDR::Concerns::ReadsBytes
3
+
4
+ #
5
+ # Serialized the provided `val` to xdr and writes it to `io`
6
+ #
7
+ # @param val [Object] The object to serialize
8
+ # @param io [IO] an IO object to write to
9
+ #
10
+ def write(val, io)
11
+ raise NotImplementedError, "implement in including class"
12
+ end
13
+
14
+ #
15
+ # Reads from the provided IO an instance of the implementing class
16
+ # @param io [IO] the io to read from
17
+ #
18
+ # @return [Object] the deserialized value
19
+ def read(io)
20
+ raise NotImplementedError, "implement in including class"
21
+ end
22
+
23
+ #
24
+ # Returns true if the value provided is compatible with this serializer class
25
+ #
26
+ # @param value [Object] the value to test
27
+ #
28
+ # @return [Boolean] true if valid, false otherwise
29
+ def valid?(value)
30
+ raise NotImplementedError, "implement in including class"
31
+ end
32
+
33
+ #
34
+ # Serialized the provided val to xdr, returning a string
35
+ # of the serialized data
36
+ #
37
+ # @param val [Object] the value to serialize
38
+ #
39
+ # @return [String] the produced bytes
40
+ def to_xdr(val)
41
+ StringIO.
42
+ new.
43
+ tap{|io| write(val, io)}.
44
+ string.force_encoding("ASCII-8BIT")
45
+ end
46
+
47
+ #
48
+ # Deserializes an object from the provided string of bytes
49
+ #
50
+ # @param string [String] the bytes to read from
51
+ #
52
+ # @return [Object] the deserialized value
53
+ def from_xdr(string)
54
+ io = StringIO.new(string)
55
+ read(io)
56
+ end
57
+
58
+ private
59
+ def padding_for(length)
60
+ case length % 4
61
+ when 0 ; 0
62
+ when 1 ; 3
63
+ when 2 ; 2
64
+ when 3 ; 1
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,5 @@
1
+ module XDR::Concerns::FloatConverter
2
+ def valid?(val)
3
+ val.is_a?(Float)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module XDR::Concerns::IntegerConverter
2
+ def valid?(val)
3
+ val.is_a?(Integer)
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ module XDR::Concerns::ReadsBytes
2
+ private
3
+ def read_bytes(io, length)
4
+ io.read(length).tap do |bytes|
5
+ raise EOFError if bytes.nil? || bytes.length != length
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module XDR::Concerns::StringConverter
2
+ def valid?(val)
3
+ val.is_a?(String)
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ module XDR::Double
2
+ extend XDR::Concerns::ConvertsToXDR
3
+ extend XDR::Concerns::FloatConverter
4
+
5
+ def self.write(val, io)
6
+ raise XDR::WriteError unless valid?(val)
7
+ io.write [val].pack("G")
8
+ end
9
+
10
+ def self.read(io)
11
+ read_bytes(io, 8).unpack("G").first
12
+ end
13
+
14
+ end
@@ -0,0 +1,7 @@
1
+ module XDR::DSL
2
+ extend ActiveSupport::Autoload
3
+
4
+ autoload :Struct
5
+ autoload :Union
6
+ autoload :Enum
7
+ end
@@ -0,0 +1,24 @@
1
+ module XDR::DSL::Enum
2
+
3
+ def member(name, value)
4
+ raise ArgumentError, "#{self} is sealed" if self.sealed
5
+ raise ArgumentError, "#{value} is not Fixnum" unless value.is_a?(Fixnum)
6
+ raise ArgumentError, "#{value} is already used" unless
7
+
8
+ name = name.to_s.underscore
9
+
10
+ instance = new(name, value)
11
+ self.members = self.members.merge(name => instance)
12
+ self.by_value = self.by_value.merge(instance.value => instance)
13
+
14
+ class_eval <<-EOS, __FILE__, __LINE__
15
+ def self.#{name}
16
+ members["#{name}"]
17
+ end
18
+ EOS
19
+ end
20
+
21
+ def seal
22
+ self.sealed = true
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ module XDR::DSL::Struct
2
+ def attribute(name, type)
3
+
4
+ unless type.is_a?(XDR::Concerns::ConvertsToXDR)
5
+ raise ArgumentError, "#{type} does not convert to xdr"
6
+ end
7
+
8
+ self.fields = self.fields.merge(name => type)
9
+
10
+ attr_accessor name
11
+ define_attribute_methods name
12
+ end
13
+ end
@@ -0,0 +1,32 @@
1
+ module XDR::DSL::Union
2
+ def switch_on(type, name)
3
+ raise ArgumentError if self.switch_type.present?
4
+ self.switch_type = type
5
+ self.switch_name = name
6
+
7
+ alias_method name, :switch
8
+ end
9
+
10
+ def switch(switch, arm=nil)
11
+ raise ArgumentError, "`switch_on` not defined yet" if self.switch_type.nil?
12
+
13
+ switch = normalize_switch(switch)
14
+ self.switches = self.switches.merge(switch => arm)
15
+ end
16
+
17
+ def attribute(name, type)
18
+ raise ArgumentError, "#{type} does not convert to xdr" unless type.is_a?(XDR::Concerns::ConvertsToXDR)
19
+
20
+ self.arms = self.arms.merge(name => type)
21
+ define_attribute_methods name
22
+ end
23
+
24
+ private
25
+ def normalize_switch(switch)
26
+ case switch
27
+ when self.switch_type ; switch
28
+ when :default ; switch
29
+ else ; self.switch_type.from_name(switch)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,48 @@
1
+ class XDR::Enum
2
+ extend XDR::Concerns::ConvertsToXDR
3
+ extend XDR::DSL::Enum
4
+
5
+ class_attribute :members
6
+ class_attribute :by_value
7
+ class_attribute :sealed
8
+ self.members = ActiveSupport::OrderedHash.new.with_indifferent_access
9
+ self.by_value = ActiveSupport::OrderedHash.new
10
+ self.sealed = false
11
+
12
+ def self.write(val, io)
13
+ raise XDR::WriteError, "Invalid enum value: #{val.inspect}" unless val.is_a?(self)
14
+
15
+ XDR::Int.write(val.value, io)
16
+ end
17
+
18
+ def self.read(io)
19
+ value = XDR::Int.read(io)
20
+ by_value[value].tap do |result|
21
+ raise XDR::EnumValueError, "Unknown #{name} member: #{value}" if result.blank?
22
+ end
23
+ end
24
+
25
+ def self.valid?(val)
26
+ val.is_a?(self)
27
+ end
28
+
29
+ def self.from_name(name)
30
+ normalized = name.to_s.underscore
31
+ members[normalized].tap do |r|
32
+ raise XDR::EnumNameError, "#{name} is not a member of #{self.name}" if r.blank?
33
+ end
34
+ end
35
+
36
+ attr_reader :name
37
+ attr_reader :value
38
+
39
+ def initialize(name, value)
40
+ raise ArgumentError, "#{self.class} is sealed" if self.sealed
41
+ @name = name
42
+ @value = value
43
+ end
44
+
45
+ def to_s
46
+ "#{self.class.name}.#{@name}(#{@value})"
47
+ end
48
+ end
@@ -0,0 +1,14 @@
1
+ module XDR::Float
2
+ extend XDR::Concerns::ConvertsToXDR
3
+ extend XDR::Concerns::FloatConverter
4
+
5
+ def self.write(val, io)
6
+ raise XDR::WriteError unless val.is_a?(Float)
7
+ io.write [val].pack("g")
8
+ end
9
+
10
+ def self.read(io)
11
+ read_bytes(io, 4).unpack("g").first
12
+ end
13
+
14
+ end
@@ -0,0 +1,14 @@
1
+ module XDR::Hyper
2
+ extend XDR::Concerns::ConvertsToXDR
3
+ extend XDR::Concerns::IntegerConverter
4
+
5
+ def self.write(val, io)
6
+ raise XDR::WriteError, "val is not Integer" unless val.is_a?(Integer)
7
+ # TODO: check bounds
8
+ io.write [val].pack("q>")
9
+ end
10
+
11
+ def self.read(io)
12
+ read_bytes(io, 8).unpack("q>").first
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module XDR::Int
2
+ extend XDR::Concerns::ConvertsToXDR
3
+ extend XDR::Concerns::IntegerConverter
4
+
5
+ def self.write(val, io)
6
+ raise XDR::WriteError, "val is not Integer" unless val.is_a?(Integer)
7
+ # TODO: check bounds
8
+ io.write [val].pack("l>")
9
+ end
10
+
11
+ def self.read(io)
12
+ read_bytes(io, 4).unpack("l>").first
13
+ end
14
+ end
@@ -0,0 +1,26 @@
1
+ #
2
+ # A thin wrapper around ActiveSupport::Autoload configured to always eager_load
3
+ # a child. By calling `load_all!` on the namespace module, all children will
4
+ # be eager loaded, allowing us to more easily operate in a multi-threaded
5
+ # environment.
6
+ #
7
+ module XDR::Namespace
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ extend ActiveSupport::Autoload
12
+ end
13
+
14
+ module ClassMethods
15
+ def load_all!
16
+ constants.each do |const_name|
17
+ begin
18
+ const = const_get const_name
19
+ const.public_send :load_all! if const.respond_to? :load_all!
20
+ rescue NameError => e
21
+ raise e unless e.message =~ /uninitialized constant #{const_name}/
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end