recursive-open-struct 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4442ce9b9b12e7e7b187a2df666cf8018c97a30d
4
- data.tar.gz: d869866022cbc4e3bc5f7ade8b2ed424010b0823
3
+ metadata.gz: 72ff48c134d3b90f56c0c2808e55f107c8bdd302
4
+ data.tar.gz: 3acf497ceb23b7b86de443dc3b4a83ddffa143eb
5
5
  SHA512:
6
- metadata.gz: 217c2af046ca66b67c2f35d513dcd05dd4e00255ec73a67f66b80acf8403c62919728cab7c255f0435cd1e7264c2e53cb57a1be1b79eacc4bb85fe0b91ca27d5
7
- data.tar.gz: f6a6aa2438f32e8f3d4021ddecd1547915702e00599475dff6e6ce6bfb23f9191f4f2400057531abfb455a0e6b1710cc184fc2884c21e9afcacca931bd13dc40
6
+ metadata.gz: 0279ca781f0607ae71c16d21589644a7b6151605f7f8cd74b47129ff2aad4c99536893375215aa9308342db54ba117ce271346bbc9c6a589c10e0f5bb105c9d1
7
+ data.tar.gz: be2d8df65e43686494858e8ab4cbec822336bcd5f68d0f87445fd968afd4ea08770e766192c489d900ae7d6b7233b9a17308da0089c7f6aa821b45e967f29a4c
data/.travis.yml CHANGED
@@ -4,4 +4,5 @@ rvm:
4
4
  - 1.9.3
5
5
  - 2.0.0
6
6
  - 2.1.0
7
+ - 2.2
7
8
  - jruby-19mode
data/CHANGELOG.md ADDED
@@ -0,0 +1,92 @@
1
+ 0.6.0 / 2015-03-28
2
+ ==================
3
+
4
+ * NEW: fervic: Make subscript notation be recursive like dot-method notation
5
+ * NEW: fervic: Added a new option, `:mutate_input_hash`, that allows the caller
6
+ to determine whether the original hash is mutated or not when a nested value
7
+ in the ROS tree is modified. If false (the default), the ROS will not modify
8
+ the original hash tree. If tree, changes within the ROS tree will also be
9
+ reflected in the hash tree.
10
+ * FIX: fervic: Setting/updating a value nested deep in an ROS tree is kept
11
+ when the top-level ROS object is duped.
12
+ * MAINT: Extracted `#deep_dup` added by fervic into its own class. This makes it
13
+ possibly easier to use/copy for others, and it cleans up the main class file.
14
+ * MAINT: Moved `#debug_inspect` out to its own module. This cleans up the main
15
+ class file a bit. It is also something I may remove if I ever have a major
16
+ version bump.
17
+ * MAINT: Adding MRI 2.2 to Travis-CI
18
+
19
+ 0.5.0 / 2014-06-14
20
+ ==================
21
+
22
+ * NEW: Tom Chapin: Added a `#to_hash` alias for `#to_h`
23
+ * MAINT: Added Travis-CI support. Testing against MRI 1.9.3, MRI 2.0, MRI 2.1,
24
+ and JRuby in 1.9 mode. Not aiming to support 1.8.7 since it has been nearly a
25
+ year since it has officially been retired.
26
+
27
+ 0.4.5 / 2013-10-23
28
+ ==================
29
+
30
+ * FIX: Matt Culpepper: Allow ROS subclasses to use their own type when creating
31
+ nested objects in the tree.
32
+
33
+ 0.4.4 / 2013-08-28
34
+ ==================
35
+
36
+ * FIX: Ensure proper file permissions when building the gem archive
37
+
38
+ 0.4.3 / 2013-05-30
39
+ ==================
40
+
41
+ * FIX: Sebastian Gaul: Make `recurse_over_arrays` option work on more
42
+ deeply-nested hashes.
43
+
44
+ 0.4.2 / 2013-05-29
45
+ ==================
46
+
47
+ * FIX: Setting a value on a nested element, then getting that value should show
48
+ the updated value
49
+ * FIX: Calling `#to_h` on the top-level ROS object also reflects changed nested
50
+ elements.
51
+
52
+ 0.4.1 / 2013-05-28
53
+ ==================
54
+
55
+ * FIX: Fixing the `spec:coverage` Rake task
56
+
57
+ 0.4.0 / 2013-05-26
58
+ ==================
59
+
60
+ * NEW: Added `#to_h`
61
+ * MAINT: Stopped using jeweler for gem development/packaging
62
+
63
+ 0.3.1 / 2012-10-23
64
+ ==================
65
+
66
+ * FIX: Cédric Felizard: Fix to make it work with MRI 1.8.7 again
67
+ * MAINT: More spec fixups to improve spec runs on MRI 1.9.3
68
+
69
+ 0.3.0 / 2013-10-23
70
+ ==================
71
+
72
+ * NEW: Matthew O'Riordan: Add support for recursion working over Arrays
73
+ * NEW: Made recursion over Arrays optional with `recurse_over_arrays` option.
74
+ * NEW: Improving `#debug_inspect` so that it can use any IO object, not just
75
+ STDOUT.
76
+ * MAINT: Much cleanup of development dependencies, README file, etc.
77
+
78
+ 0.2.1 / 2011-05-31
79
+ ==================
80
+
81
+ * FIX: Offirmo: Slight improvement for `#debug_inspect`
82
+
83
+ 0.2.0 / 2011-05-25
84
+ ==================
85
+
86
+ * NEW: Offirmo: Added `debug_inspect`
87
+ * MAINT: Offirmo: Worked the development files so that it can be built as a gem
88
+
89
+ 0.1.0 / 2010-01-12
90
+ ==================
91
+
92
+ * Initial release
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 William (B.J.) Snow Orvis
1
+ Copyright (c) 2009-2015 William (B.J.) Snow Orvis
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,4 +1,4 @@
1
- = recursive-open-struct
1
+ # recursive-open-struct
2
2
 
3
3
  OpenStruct subclass that returns nested hash attributes as
4
4
  RecursiveOpenStructs.
@@ -23,7 +23,7 @@ have to explicitly enable it:
23
23
  ros.somarr[0].name # => 'a'
24
24
  ros.somarr[1].name # => 'b'
25
25
 
26
- == Installation
26
+ ## Installation
27
27
 
28
28
  Available as a gem in rubygems, the default gem repository.
29
29
 
@@ -35,16 +35,14 @@ You may also install the gem manually :
35
35
 
36
36
  gem install recursive-open-struct
37
37
 
38
- == Note on Patches/Pull Requests
38
+ ## Contributing
39
39
 
40
40
  * Fork the project.
41
41
  * Make your feature addition or bug fix.
42
- * Add tests for it. This is important so I don't break it in a
43
- future version unintentionally.
44
- * Commit, do not mess with rakefile, version, or history.
45
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
42
+ * Add tests for your new or changed functionality. Make sure the tests you add
43
+ provide clean and clear explanation of the feature.
46
44
  * Send me a pull request. Bonus points for topic branches.
47
45
 
48
- == Copyright
46
+ ## Copyright
49
47
 
50
- Copyright (c) 2010 William (B.J.) Snow Orvis. See LICENSE for details.
48
+ Copyright (c) 2009-2015 William (B.J.) Snow Orvis. See LICENSE for details.
@@ -1,11 +1,22 @@
1
1
  require 'ostruct'
2
+ require 'recursive_open_struct/version'
3
+
4
+ require 'recursive_open_struct/debug_inspect'
5
+ require 'recursive_open_struct/deep_dup'
2
6
 
3
7
  class RecursiveOpenStruct < OpenStruct
4
- VERSION = "0.5.0"
8
+ include DebugInspect
9
+
10
+ def initialize(hash=nil, args={})
11
+ @recurse_over_arrays = args.fetch(:recurse_over_arrays, false)
12
+ mutate_input_hash = args.fetch(:mutate_input_hash, false)
13
+
14
+ unless mutate_input_hash
15
+ hash = DeepDup.new(recurse_over_arrays: @recurse_over_arrays).call(hash)
16
+ end
17
+
18
+ super(hash)
5
19
 
6
- def initialize(h=nil, args={})
7
- @recurse_over_arrays = args.fetch(:recurse_over_arrays,false)
8
- super(h)
9
20
  @sub_elements = {}
10
21
  end
11
22
 
@@ -23,6 +34,10 @@ class RecursiveOpenStruct < OpenStruct
23
34
 
24
35
  alias_method :to_hash, :to_h
25
36
 
37
+ def [](name)
38
+ send name
39
+ end
40
+
26
41
  def new_ostruct_member(name)
27
42
  name = name.to_sym
28
43
  unless self.respond_to?(name)
@@ -30,9 +45,11 @@ class RecursiveOpenStruct < OpenStruct
30
45
  define_method(name) do
31
46
  v = @table[name]
32
47
  if v.is_a?(Hash)
33
- @sub_elements[name] ||= self.class.new(v, :recurse_over_arrays => @recurse_over_arrays)
48
+ @sub_elements[name] ||= self.class.new(v,
49
+ :recurse_over_arrays => @recurse_over_arrays,
50
+ :mutate_input_hash => true)
34
51
  elsif v.is_a?(Array) and @recurse_over_arrays
35
- @sub_elements[name] ||= recurse_over_array v
52
+ @sub_elements[name] ||= recurse_over_array(v)
36
53
  else
37
54
  v
38
55
  end
@@ -44,10 +61,11 @@ class RecursiveOpenStruct < OpenStruct
44
61
  name
45
62
  end
46
63
 
47
- def recurse_over_array array
64
+ # TODO: Make me private if/when we do an API-breaking change release
65
+ def recurse_over_array(array)
48
66
  array.map do |a|
49
67
  if a.is_a? Hash
50
- self.class.new(a, :recurse_over_arrays => true)
68
+ self.class.new(a, :recurse_over_arrays => true, :mutate_input_hash => true)
51
69
  elsif a.is_a? Array
52
70
  recurse_over_array a
53
71
  else
@@ -55,41 +73,5 @@ class RecursiveOpenStruct < OpenStruct
55
73
  end
56
74
  end
57
75
  end
58
-
59
- def debug_inspect(io = STDOUT, indent_level = 0, recursion_limit = 12)
60
- display_recursive_open_struct(io, @table, indent_level, recursion_limit)
61
- end
62
-
63
- def display_recursive_open_struct(io, ostrct_or_hash, indent_level, recursion_limit)
64
-
65
- if recursion_limit <= 0 then
66
- # protection against recursive structure (like in the tests)
67
- io.puts ' '*indent_level + '(recursion limit reached)'
68
- else
69
- #puts ostrct_or_hash.inspect
70
- if ostrct_or_hash.is_a?(self.class) then
71
- ostrct_or_hash = ostrct_or_hash.marshal_dump
72
- end
73
-
74
- # We'll display the key values like this : key = value
75
- # to align display, we look for the maximum key length of the data that will be displayed
76
- # (everything except hashes)
77
- data_indent = ostrct_or_hash \
78
- .reject { |k, v| v.is_a?(self.class) || v.is_a?(Hash) } \
79
- .max {|a,b| a[0].to_s.length <=> b[0].to_s.length}[0].to_s.length
80
- # puts "max length = #{data_indent}"
81
-
82
- ostrct_or_hash.each do |key, value|
83
- if (value.is_a?(self.class) || value.is_a?(Hash)) then
84
- io.puts ' '*indent_level + key.to_s + '.'
85
- display_recursive_open_struct(io, value, indent_level + 1, recursion_limit - 1)
86
- else
87
- io.puts ' '*indent_level + key.to_s + ' '*(data_indent - key.to_s.length) + ' = ' + value.inspect
88
- end
89
- end
90
- end
91
-
92
- true
93
- end
94
-
95
76
  end
77
+
@@ -0,0 +1,38 @@
1
+ module RecursiveOpenStruct::DebugInspect
2
+ def debug_inspect(io = STDOUT, indent_level = 0, recursion_limit = 12)
3
+ display_recursive_open_struct(io, @table, indent_level, recursion_limit)
4
+ end
5
+
6
+ def display_recursive_open_struct(io, ostrct_or_hash, indent_level, recursion_limit)
7
+
8
+ if recursion_limit <= 0 then
9
+ # protection against recursive structure (like in the tests)
10
+ io.puts ' '*indent_level + '(recursion limit reached)'
11
+ else
12
+ #puts ostrct_or_hash.inspect
13
+ if ostrct_or_hash.is_a?(self.class) then
14
+ ostrct_or_hash = ostrct_or_hash.marshal_dump
15
+ end
16
+
17
+ # We'll display the key values like this : key = value
18
+ # to align display, we look for the maximum key length of the data that will be displayed
19
+ # (everything except hashes)
20
+ data_indent = ostrct_or_hash \
21
+ .reject { |k, v| v.is_a?(self.class) || v.is_a?(Hash) } \
22
+ .max {|a,b| a[0].to_s.length <=> b[0].to_s.length}[0].to_s.length
23
+ # puts "max length = #{data_indent}"
24
+
25
+ ostrct_or_hash.each do |key, value|
26
+ if (value.is_a?(self.class) || value.is_a?(Hash)) then
27
+ io.puts ' '*indent_level + key.to_s + '.'
28
+ display_recursive_open_struct(io, value, indent_level + 1, recursion_limit - 1)
29
+ else
30
+ io.puts ' '*indent_level + key.to_s + ' '*(data_indent - key.to_s.length) + ' = ' + value.inspect
31
+ end
32
+ end
33
+ end
34
+
35
+ true
36
+ end
37
+
38
+ end
@@ -0,0 +1,30 @@
1
+ class RecursiveOpenStruct::DeepDup
2
+ def initialize(opts={})
3
+ @recurse_over_arrays = opts.fetch(:recurse_over_arrays, false)
4
+ end
5
+
6
+ def call(obj)
7
+ deep_dup(obj)
8
+ end
9
+
10
+ private
11
+
12
+ def deep_dup(obj, visited=[])
13
+ if obj.is_a?(Hash)
14
+ obj.each_with_object({}) do |(key, value), h|
15
+ h[key] = value_or_deep_dup(value, visited)
16
+ end
17
+ elsif obj.is_a?(Array) && @recurse_over_arrays
18
+ obj.each_with_object([]) do |value, arr|
19
+ arr << value_or_deep_dup(value, visited)
20
+ end
21
+ else
22
+ obj
23
+ end
24
+ end
25
+
26
+ def value_or_deep_dup(value, visited)
27
+ obj_id = value.object_id
28
+ visited.include?(obj_id) ? value : deep_dup(value, visited << obj_id)
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ # Necessary since the top-level class/module is a class that inherits from
2
+ # OpenStruct.
3
+ require 'ostruct'
4
+
5
+ class RecursiveOpenStruct < OpenStruct
6
+ VERSION = "0.6.0"
7
+ end
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
- require './lib/recursive_open_struct'
3
+ require './lib/recursive_open_struct/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "recursive-open-struct"
@@ -29,11 +29,12 @@ Gem::Specification.new do |s|
29
29
  s.test_files = `git ls-files spec`.split("\n")
30
30
  s.require_paths = ["lib"]
31
31
  s.extra_rdoc_files = [
32
+ "CHANGELOG.md",
32
33
  "LICENSE.txt",
33
- "README.rdoc"
34
+ "README.md"
34
35
  ]
35
36
 
36
- s.add_development_dependency(%q<rspec>, [">= 0"])
37
+ s.add_development_dependency('rspec', "~> 3.2")
37
38
  s.add_development_dependency(%q<bundler>, [">= 0"])
38
39
  s.add_development_dependency(%q<rdoc>, [">= 0"])
39
40
  s.add_development_dependency(%q<rake>, [">= 0"])
@@ -64,6 +64,10 @@ describe RecursiveOpenStruct do
64
64
  subject.blah.another.should == 'value'
65
65
  end
66
66
 
67
+ it "handles subscript notation the same way as dotted notation" do
68
+ subject.blah.another.should == subject[:blah].another
69
+ end
70
+
67
71
  it "uses #key_as_a_hash to return key as a Hash" do
68
72
  subject.blah_as_a_hash.should == { :another => 'value' }
69
73
  end
@@ -96,19 +100,30 @@ describe RecursiveOpenStruct do
96
100
 
97
101
  context "after a sub-element has been modified" do
98
102
  let(:hash) do
99
- {
100
- :blah => {
101
- :blargh => 'Brad'
102
- }
103
- }
103
+ { :blah => { :blargh => "Brad" }, :some_array => [ 1, 2, 3] }
104
+ end
105
+ let(:updated_hash) do
106
+ { :blah => { :blargh => "Janet" }, :some_array => [ 1, 2, 3] }
104
107
  end
108
+
105
109
  subject { RecursiveOpenStruct.new(hash) }
110
+
106
111
  before(:each) { subject.blah.blargh = "Janet" }
107
- it "returns a hash that contains those modifications" do
108
- subject.to_h.should == { :blah => { :blargh => "Janet" } }
112
+
113
+ it "returns a hash tree that contains those modifications" do
114
+ subject.to_h.should == updated_hash
115
+ end
116
+
117
+ it "does not mutate the input hash tree passed to the constructor" do
118
+ hash[:blah][:blargh].should == 'Brad'
109
119
  end
110
- end
111
120
 
121
+ it "limits the deep-copy to the initial hash tree" do
122
+ subject.some_array[0] = 4
123
+
124
+ hash[:some_array][0].should == 4
125
+ end
126
+ end
112
127
 
113
128
  describe 'recursing over arrays' do
114
129
  let(:blah_list) { [ { :foo => '1' }, { :foo => '2' }, 'baz' ] }
@@ -122,15 +137,30 @@ describe RecursiveOpenStruct do
122
137
  it { subject.blah[1].foo.should == '2' }
123
138
  it { subject.blah_as_a_hash.should == blah_list }
124
139
  it { subject.blah[2].should == 'baz' }
125
- it "Retains changes across Array lookups" do
126
- subject.blah[1].foo = "Dr Scott"
127
- subject.blah[1].foo.should == "Dr Scott"
128
- end
129
- it "propagates the changes through to .to_h across Array lookups" do
130
- subject.blah[1].foo = "Dr Scott"
131
- subject.to_h.should == {
132
- :blah => [ { :foo => '1' }, { :foo => "Dr Scott" }, 'baz' ]
133
- }
140
+
141
+ context "when an inner value changes" do
142
+ let(:updated_blah_list) { [ { :foo => '1' }, { :foo => 'Dr Scott' }, 'baz' ] }
143
+ let(:updated_h) { { :blah => updated_blah_list } }
144
+
145
+ before(:each) { subject.blah[1].foo = "Dr Scott" }
146
+
147
+ it "Retains changes across Array lookups" do
148
+ subject.blah[1].foo.should == "Dr Scott"
149
+ end
150
+
151
+ it "propagates the changes through to .to_h across Array lookups" do
152
+ subject.to_h.should == {
153
+ :blah => [ { :foo => '1' }, { :foo => "Dr Scott" }, 'baz' ]
154
+ }
155
+ end
156
+
157
+ it "does not mutate the input hash passed to the constructor" do
158
+ h[:blah][1][:foo].should == '2'
159
+ end
160
+
161
+ it "the deep copy recurses over Arrays as well" do
162
+ h[:blah][1][:foo].should == '2'
163
+ end
134
164
  end
135
165
 
136
166
  context "when array is nested deeper" do
data/spec/spec_helper.rb CHANGED
@@ -12,7 +12,7 @@ end
12
12
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
13
13
 
14
14
  RSpec.configure do |config|
15
- config.treat_symbols_as_metadata_keys_with_true_values = true
16
15
  config.run_all_when_everything_filtered = true
17
16
  config.filter_run :focus
17
+ config.expect_with(:rspec) { |c| c.syntax = :should }
18
18
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recursive-open-struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - William (B.J.) Snow Orvis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-14 00:00:00.000000000 Z
11
+ date: 2015-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '3.2'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '3.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -81,19 +81,24 @@ email: aetherknight@gmail.com
81
81
  executables: []
82
82
  extensions: []
83
83
  extra_rdoc_files:
84
+ - CHANGELOG.md
84
85
  - LICENSE.txt
85
- - README.rdoc
86
+ - README.md
86
87
  files:
87
88
  - .document
88
89
  - .gitignore
89
90
  - .rspec
90
91
  - .travis.yml
92
+ - CHANGELOG.md
91
93
  - Gemfile
92
94
  - LICENSE.txt
93
- - README.rdoc
95
+ - README.md
94
96
  - Rakefile
95
97
  - lib/recursive-open-struct.rb
96
98
  - lib/recursive_open_struct.rb
99
+ - lib/recursive_open_struct/debug_inspect.rb
100
+ - lib/recursive_open_struct/deep_dup.rb
101
+ - lib/recursive_open_struct/version.rb
97
102
  - recursive-open-struct.gemspec
98
103
  - spec/recursive_open_struct_spec.rb
99
104
  - spec/spec_helper.rb