firm 0.9.3 → 0.9.7

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,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c1c7b999e2db422d608d8aaf8e28a9bace6824640f50a8e5dabb30e2ca89a36
4
- data.tar.gz: a16d62247a09cc2e1d8b3c4d2a990ffefb7b48c18f6f1d8f27e12c770ff103eb
3
+ metadata.gz: 8a4a4e31a319e92f4e5efb708562832f1072602084f5c0b4907c88d1e28d2c1b
4
+ data.tar.gz: 0e9e64b8fb301c3f895fe0b76978d6794389d0ca651339fd132396866d05eefa
5
5
  SHA512:
6
- metadata.gz: 6c45a0bc530a143ad8b37de7e00f6fdd4a2af91ffb52b18ce86f91ffac390ea05825d58b042e29361a96fd762be58d210d141bdb88d9748c3232e7c30232b8cc
7
- data.tar.gz: 939fe265f4f55f1255851e5f246b73ca416c6649af2ffcdad6aa8fb63341289ef64c71678bc02a7372c66acd6a91a26111ebc049d2a571b5f3f189f7010d3fb2
6
+ metadata.gz: 6144308bc7ba7bba7cac24c173a8fbabcac75e3074d29205593c64173696c7b9c41b47c5747b1265ad680f437d87abbce400e9ea0f311b8417403be4faeb55a8
7
+ data.tar.gz: 32353706f381e81dcacb705bbe144464fef1233df920dcb45d21e3386fca873bbd6ae52b7a1825cff84fec88d43a68935c89ad7577e9fa8f31f1e618c6cba8c4
data/README.md CHANGED
@@ -43,6 +43,10 @@ FIRM supports (de-)serializing many core Ruby objects out of the box including:
43
43
  - `Date`
44
44
  - `DateTime`
45
45
 
46
+ For security reasons FIRM does **not** support direct (de-)serializing of `Class` objects but will rather
47
+ serialize (and deserialize) these as their scoped string names. Customized property setters can be used to
48
+ resolve Class objects from these names if really needed.
49
+
46
50
  FIRM also supports a simple scheme to provide (de-)serialization support for user defined classes.
47
51
 
48
52
  FIRM provides object aliasing support for JSON and XML in a similar fashion as the standard support provided
@@ -143,6 +143,12 @@ module FIRM
143
143
 
144
144
  class << self
145
145
 
146
+ TLS_VARS_KEY = :firm_tls_vars.freeze
147
+
148
+ def tls_vars
149
+ Thread.current[TLS_VARS_KEY] ||= {}
150
+ end
151
+
146
152
  def serializables
147
153
  @serializables ||= ::Set.new
148
154
  end
@@ -198,7 +204,7 @@ module FIRM
198
204
  private_constant :TLS_ALIAS_STACK_KEY
199
205
 
200
206
  def anchor_object_registry_stack
201
- ::Thread.current[TLS_ANCHOR_OBJECTS_KEY] ||= []
207
+ Serializable.tls_vars[TLS_ANCHOR_OBJECTS_KEY] ||= []
202
208
  end
203
209
  private :anchor_object_registry_stack
204
210
 
@@ -252,7 +258,7 @@ module FIRM
252
258
  end
253
259
 
254
260
  def anchor_references_stack
255
- ::Thread.current[TLS_ALIAS_STACK_KEY] ||= []
261
+ Serializable.tls_vars[TLS_ALIAS_STACK_KEY] ||= []
256
262
  end
257
263
  private :anchor_references_stack
258
264
 
@@ -658,9 +664,8 @@ module FIRM
658
664
  derived.class_eval <<~__CODE
659
665
  module SerializerMethods
660
666
  def for_serialize(hash, excludes = ::Set.new)
661
- hash = super(hash, excludes | #{derived.name}.excluded_serializer_properties)
662
667
  #{derived.name}.serializer_properties.each { |prop| prop.serialize(self, hash, excludes) }
663
- hash
668
+ super(hash, excludes | #{derived.name}.excluded_serializer_properties)
664
669
  end
665
670
  protected :for_serialize
666
671
 
@@ -70,7 +70,7 @@ module FIRM
70
70
  private_constant :TLS_PARSE_STACK_KEY
71
71
 
72
72
  def safe_deserialize
73
- ::Thread.current[TLS_SAFE_DESERIALIZE_KEY] ||= []
73
+ Serializable.tls_vars[TLS_SAFE_DESERIALIZE_KEY] ||= []
74
74
  end
75
75
  private :safe_deserialize
76
76
 
@@ -83,7 +83,7 @@ module FIRM
83
83
  end
84
84
 
85
85
  def parse_stack
86
- ::Thread.current[TLS_PARSE_STACK_KEY] ||= []
86
+ Serializable.tls_vars[TLS_PARSE_STACK_KEY] ||= []
87
87
  end
88
88
  private :parse_stack
89
89
 
@@ -20,7 +20,7 @@ module FIRM
20
20
  private_constant :TLS_STATE_KEY
21
21
 
22
22
  def xml_state
23
- ::Thread.current[TLS_STATE_KEY] ||= []
23
+ Serializable.tls_vars[TLS_STATE_KEY] ||= []
24
24
  end
25
25
  private :xml_state
26
26
 
@@ -133,6 +133,22 @@ module FIRM
133
133
  end
134
134
  end
135
135
 
136
+ # registered as tag 'Class' but that is never actually used
137
+ define_xml_handler(::Class, 'Class') do
138
+ # overload to emit 'String' tags
139
+ def create_type_node(xml)
140
+ xml.add_child(Nokogiri::XML::Node.new('String', xml.document))
141
+ end
142
+ def to_xml(xml, value)
143
+ create_type_node(xml).add_child(Nokogiri::XML::CDATA.new(xml.document, value.name))
144
+ xml
145
+ end
146
+ def from_xml(xml)
147
+ # should never be called
148
+ raise Serializable::Exception, 'Unsupported Class deserialization'
149
+ end
150
+ end
151
+
136
152
  define_xml_handler(::NilClass, :nil) do
137
153
  def to_xml(xml, _value)
138
154
  create_type_node(xml)
@@ -68,8 +68,26 @@ module FIRM
68
68
  end
69
69
  end
70
70
 
71
+ # Derived Psych YAMLTree class to emit simple strings for
72
+ # Class instances
73
+ class NoClassYAMLTree < ::Psych::Visitors::YAMLTree
74
+
75
+ def visit_Class(o)
76
+ raise TypeError, "can't dump anonymous module: #{o}" unless o.name
77
+ visit_String(o.name)
78
+ end
79
+
80
+ def visit_Module(o)
81
+ raise TypeError, "can't dump anonymous class: #{o}" unless o.name
82
+ visit_String(o.name)
83
+ end
84
+
85
+ end
86
+
71
87
  def self.dump(obj, io=nil, **)
72
- ::YAML.dump(obj, io)
88
+ visitor = YAML::NoClassYAMLTree.create
89
+ visitor << obj
90
+ visitor.tree.yaml io
73
91
  end
74
92
 
75
93
  def self.load(source)
data/lib/firm/version.rb CHANGED
@@ -4,6 +4,6 @@
4
4
  module FIRM
5
5
 
6
6
  # FIRM version
7
- VERSION = "0.9.3"
7
+ VERSION = "0.9.7"
8
8
 
9
9
  end
@@ -292,6 +292,17 @@ module SerializerTestMixin
292
292
 
293
293
  end
294
294
 
295
+ def test_class
296
+
297
+ obj_serial = [Point, Colour].serialize
298
+ obj_new = assert_nothing_raised { FIRM.deserialize(obj_serial) }
299
+ assert_instance_of(::Array, obj_new)
300
+ assert_true(obj_new.all? { |e| String === e })
301
+ assert_equal(Point.name, obj_new[0])
302
+ assert_equal(Colour.name, obj_new[1])
303
+
304
+ end
305
+
295
306
  class PointsOwner
296
307
  include FIRM::Serializable
297
308
 
@@ -596,6 +607,90 @@ module SerializerTestMixin
596
607
  assert_equal(obj_new.map[:five].object_id, obj_new.map[:six].object_id)
597
608
  end
598
609
 
610
+ class Shape
611
+ include FIRM::Serializable
612
+ property :kind
613
+
614
+ def initialize(kind = :circle)
615
+ @kind = kind
616
+ end
617
+
618
+ attr_accessor :kind
619
+ end
620
+
621
+ class ShapeOwner
622
+ include FIRM::Serializable
623
+ property :shapes
624
+ def initialize
625
+ @shapes = []
626
+ end
627
+
628
+ attr_accessor :shapes
629
+ end
630
+
631
+ class Grid < ShapeOwner
632
+ property :dimensions
633
+ property :cells
634
+
635
+ DIMENSIONS = Struct.new(:rows, :columns)
636
+
637
+ def initialize(rows=nil, columns=nil)
638
+ super()
639
+ @dimensions = DIMENSIONS.new(rows || 3, columns || 3)
640
+ @cells = ::Array.new(@dimensions.rows*@dimensions.columns)
641
+ end
642
+
643
+ attr_reader :dimensions
644
+
645
+ def place_shape_at(row, col, shape)
646
+ shapes << shape
647
+ @cells[(row*dimensions.columns)+col] = shape
648
+ self
649
+ end
650
+
651
+ def get_shape_at(row, col)
652
+ @cells.at((row*dimensions.columns)+col)
653
+ end
654
+
655
+
656
+ private
657
+
658
+ def set_dimensions(dimensions)
659
+ @dimensions = dimensions
660
+ end
661
+
662
+ def get_cells
663
+ @cells
664
+ end
665
+
666
+ def set_cells(cells)
667
+ @cells = cells
668
+ end
669
+ end
670
+
671
+ def test_inherited_aliases
672
+
673
+ grid = Grid.new(2,2)
674
+ .place_shape_at(0, 0, Shape.new(:circle))
675
+ .place_shape_at(0, 1, Shape.new(:rect))
676
+ .place_shape_at(1,0, Shape.new(:cross))
677
+ .place_shape_at(1,1, Shape.new(:diamond))
678
+ obj_serial = grid.serialize
679
+ grid_new = assert_nothing_raised { FIRM.deserialize(obj_serial) }
680
+ assert_instance_of(Grid, grid_new)
681
+ assert_equal(4, grid_new.shapes.size)
682
+ assert_equal(:circle, grid_new.get_shape_at(0, 0).kind)
683
+ assert_equal(:rect, grid_new.get_shape_at(0, 1).kind)
684
+ assert_equal(:cross, grid_new.get_shape_at(1, 0).kind)
685
+ assert_equal(:diamond, grid_new.get_shape_at(1, 1).kind)
686
+ 2.times do |r|
687
+ 2.times do |c|
688
+ assert_true(grid_new.shapes.include?(grid_new.get_shape_at(r, c)))
689
+ end
690
+ end
691
+
692
+ end
693
+
599
694
  class House
600
695
 
601
696
  include FIRM::Serializable
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: firm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Corino
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-14 00:00:00.000000000 Z
11
+ date: 2024-09-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake