recursive-open-struct-sd 1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5244992a3f5ff4094c1b2b2cb3daa2e9784e3e6f
4
+ data.tar.gz: 11d6e66b3fda35da43f246d86ad6b8f82ce38acc
5
+ SHA512:
6
+ metadata.gz: e106b2c0a0b66e0c6789bd73b3c1aa82c5abf38f45aee8c0942f4f773edc4d87d1986b9c7db4d174c77d996c322422e3d758abc20bc36af2ae7a85a9f6a94cbe
7
+ data.tar.gz: 24d7faf9c8502bf0316d35abf1f31dd8a5d5571f72de98dc900d545e0dbfcb4fe6fde19f50471709c19d85f8e0e3534d63ef171edb707711ce7b79a2b87c24c6
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,50 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+
14
+ # jeweler generated
15
+ pkg
16
+
17
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
18
+ #
19
+ # * Create a file at ~/.gitignore
20
+ # * Include files you want ignored
21
+ # * Run: git config --global core.excludesfile ~/.gitignore
22
+ #
23
+ # After doing this, these files will be ignored in all your git projects,
24
+ # saving you from having to 'pollute' every project you touch with them
25
+ #
26
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
27
+ #
28
+ # For MacOS:
29
+ #
30
+ .DS_Store
31
+
32
+ # For TextMate
33
+ *.tmproj
34
+ tmtags
35
+
36
+ # For emacs:
37
+ *~
38
+ \#*
39
+ .\#*
40
+
41
+ # For vim:
42
+ *.swp
43
+
44
+ # For redcar:
45
+ #.redcar
46
+
47
+ # For rubinius:
48
+ #*.rbc
49
+
50
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ ---
2
+ language: ruby
3
+ rvm:
4
+ - 2.0.0
5
+ - 2.1.10
6
+ - 2.2.5
7
+ - 2.3.1
8
+ - 2.4.0
9
+ - ruby-head
10
+ - jruby-19mode
11
+ - jruby-9.0.5.0
12
+ - jruby-head
13
+ sudo: false
data/AUTHORS.txt ADDED
@@ -0,0 +1,15 @@
1
+ Recursive-open-struct was written by these fine people:
2
+
3
+ * Cédric Felizard <cedric@felizard.fr>
4
+ * Federico Aloi <federico.aloi@gmail.com>
5
+ * fervic <roberto@runawaybit.com>
6
+ * Kris Dekeyser <kris.dekeyser@libis.be>
7
+ * Matt Culpepper <matt@culpepper.co>
8
+ * Matthew O'Riordan <matthew.oriordan@gmail.com>
9
+ * Offirmo <offirmo.net@gmail.com>
10
+ * Peter Yeremenko <peter.yeremenko@gmail.com>
11
+ * Sebastian Gaul <sebastian@mgvmedia.com>
12
+ * Thiago Guimaraes <thiagogsr@gmail.com>
13
+ * Tom Chapin <tchapin@gmail.com>
14
+ * Victor Guzman <victor.guzman@runawaybit.com>
15
+ * William (B.J.) Snow Orvis <aetherknight@gmail.com>
data/CHANGELOG.md ADDED
@@ -0,0 +1,151 @@
1
+ 1.0.1 / 2016-01-18
2
+ ==================
3
+
4
+ * FIX [#42](https://github.com/aetherknight/recursive-open-struct/issues/42):
5
+ `[]` tried to call private methods if they existed instead of triggering the
6
+ `method_missing` code path. Thanks to @SaltwaterC for reporting.
7
+
8
+ 1.0.0 / 2015-12-11
9
+ ==================
10
+
11
+ * API-Breaking Change: Frederico Aloi: Change `to_h` to always return symbol
12
+ keys. This is more consistent with OpenStruct.
13
+ * API-Breaking Change: No longer officially supporting Ruby 1.9.3.
14
+ * NEW/FIX: Kris Dekeyser: Ensure that ROS continues to work with the new
15
+ version of OpenStruct included in dev versions of Ruby 2.2.x and Ruby 2.3. It
16
+ now implements lazy attribute creation, which broke ROS.
17
+ * NEW: Added `preserve_original_keys` option to revert to the 0.x behavior. Set
18
+ it to true if you want methods like `to_h` to return strings and perhaps
19
+ other non-symbols.
20
+ * NEW: Ensuring support for Ruby 2.0.0+ including the upcoming 2.3 release and
21
+ JRuby 9000.
22
+ * FIX: Peter Yeremenko: Fix a mistake in one of the examples in the README
23
+
24
+ 0.6.5 / 2015-06-30
25
+ ==================
26
+
27
+ * FIX: Fix ROS when initialized with nil instead of a hash.
28
+
29
+ 0.6.4 / 2015-05-20
30
+ ==================
31
+
32
+ * FIX: Kris Dekeyser: Fix indifferent subscript access (string or symbol). Also
33
+ backported several ostruct methods for Ruby 1.9.x.
34
+ * FIX: Partial fix for allowing an array in a RecursiveOpenStruct tree to be
35
+ modified. However, methods such as to_hash are still broken.
36
+
37
+ 0.6.3 / 2015-04-11
38
+ ==================
39
+
40
+ * FIX: Thiago Guimaraes: Restore being able to create an ROS from a hash that
41
+ contains strings for keys instead of symbols for keys.
42
+
43
+ 0.6.2 / 2015-04-07
44
+ ==================
45
+
46
+ * FIX: fervic: Address a bug in the Ruby 1.9's version of OpenStruct's `dup`
47
+ * FIX: Victor Guzman: Reset memoized values on assignment in order to force the
48
+ implementation to re-memoize them.
49
+ * MAINT: fervic: Simplified `initialize`
50
+
51
+ 0.6.1 / 2015-03-28
52
+ ==================
53
+
54
+ * FIX: Actually ensure that the internal @table is properly dependent or
55
+ independent of the input hash tree. I mistakenly refactored away an important
56
+ piece of code that fervic added.
57
+ * FIX: Actually ensure that `#dup` works.
58
+ * Also refactored how `#to_h` is implemented to use newer plumbing.
59
+
60
+ 0.6.0 / 2015-03-28
61
+ ==================
62
+
63
+ * NEW: fervic: Make subscript notation be recursive like dot-method notation
64
+ * NEW: fervic: Added a new option, `:mutate_input_hash`, that allows the caller
65
+ to determine whether the original hash is mutated or not when a nested value
66
+ in the ROS tree is modified. If false (the default), the ROS will not modify
67
+ the original hash tree. If tree, changes within the ROS tree will also be
68
+ reflected in the hash tree.
69
+ * FIX: fervic: Setting/updating a value nested deep in an ROS tree is kept
70
+ when the top-level ROS object is duped.
71
+ * MAINT: Extracted `#deep_dup` added by fervic into its own class. This makes it
72
+ possibly easier to use/copy for others, and it cleans up the main class file.
73
+ * MAINT: Moved `#debug_inspect` out to its own module. This cleans up the main
74
+ class file a bit. It is also something I may remove if I ever have a major
75
+ version bump.
76
+ * MAINT: Adding MRI 2.2 to Travis-CI
77
+
78
+ 0.5.0 / 2014-06-14
79
+ ==================
80
+
81
+ * NEW: Tom Chapin: Added a `#to_hash` alias for `#to_h`
82
+ * MAINT: Added Travis-CI support. Testing against MRI 1.9.3, MRI 2.0, MRI 2.1,
83
+ and JRuby in 1.9 mode. Not aiming to support 1.8.7 since it has been nearly a
84
+ year since it has officially been retired.
85
+
86
+ 0.4.5 / 2013-10-23
87
+ ==================
88
+
89
+ * FIX: Matt Culpepper: Allow ROS subclasses to use their own type when creating
90
+ nested objects in the tree.
91
+
92
+ 0.4.4 / 2013-08-28
93
+ ==================
94
+
95
+ * FIX: Ensure proper file permissions when building the gem archive
96
+
97
+ 0.4.3 / 2013-05-30
98
+ ==================
99
+
100
+ * FIX: Sebastian Gaul: Make `recurse_over_arrays` option work on more
101
+ deeply-nested hashes.
102
+
103
+ 0.4.2 / 2013-05-29
104
+ ==================
105
+
106
+ * FIX: Setting a value on a nested element, then getting that value should show
107
+ the updated value
108
+ * FIX: Calling `#to_h` on the top-level ROS object also reflects changed nested
109
+ elements.
110
+
111
+ 0.4.1 / 2013-05-28
112
+ ==================
113
+
114
+ * FIX: Fixing the `spec:coverage` Rake task
115
+
116
+ 0.4.0 / 2013-05-26
117
+ ==================
118
+
119
+ * NEW: Added `#to_h`
120
+ * MAINT: Stopped using jeweler for gem development/packaging
121
+
122
+ 0.3.1 / 2012-10-23
123
+ ==================
124
+
125
+ * FIX: Cédric Felizard: Fix to make it work with MRI 1.8.7 again
126
+ * MAINT: More spec fixups to improve spec runs on MRI 1.9.3
127
+
128
+ 0.3.0 / 2013-10-23
129
+ ==================
130
+
131
+ * NEW: Matthew O'Riordan: Add support for recursion working over Arrays
132
+ * NEW: Made recursion over Arrays optional with `recurse_over_arrays` option.
133
+ * NEW: Improving `#debug_inspect` so that it can use any IO object, not just
134
+ STDOUT.
135
+ * MAINT: Much cleanup of development dependencies, README file, etc.
136
+
137
+ 0.2.1 / 2011-05-31
138
+ ==================
139
+
140
+ * FIX: Offirmo: Slight improvement for `#debug_inspect`
141
+
142
+ 0.2.0 / 2011-05-25
143
+ ==================
144
+
145
+ * NEW: Offirmo: Added `debug_inspect`
146
+ * MAINT: Offirmo: Worked the development files so that it can be built as a gem
147
+
148
+ 0.1.0 / 2010-01-12
149
+ ==================
150
+
151
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2009-2016, The Recursive-open-struct developers (given in the
2
+ file AUTHORS.txt).
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # recursive-open-struct-sd
2
+
3
+ OpenStruct subclass that returns nested hash attributes as
4
+ RecursiveOpenStructs.
5
+
6
+ It allows for hashes within hashes to be called in a chain of methods:
7
+
8
+ ros = RecursiveOpenStruct.new( { fooa: { foob: 'fooc' } } )
9
+
10
+ ros.fooa.foob # => 'fooc'
11
+
12
+ Also, if needed, nested hashes can still be accessed as hashes:
13
+
14
+ ros.fooa_as_a_hash # { foob: 'fooc' }
15
+
16
+ RecursiveOpenStruct can also optionally recurse across arrays, although you
17
+ have to explicitly enable it:
18
+
19
+ h = { :somearr => [ { name: 'a'}, { name: 'b' } ] }
20
+ ros = RecursiveOpenStruct.new(h, recurse_over_arrays: true )
21
+
22
+ ros.somearr[0].name # => 'a'
23
+ ros.somearr[1].name # => 'b'
24
+
25
+ Also, by default it will turn all hash keys into symbols internally:
26
+
27
+ h = { 'fear' => 'is', 'the' => 'mindkiller' } }
28
+ ros = RecursiveOpenStruct.new(h)
29
+ ros.to_h # => { fear: 'is', the: 'mindkiller' }
30
+
31
+ You can preserve the original keys by enabling `:preserve_original_keys`:
32
+
33
+ h = { 'fear' => 'is', 'the' => 'mindkiller' } }
34
+ ros = RecursiveOpenStruct.new(h, preserve_original_keys: true)
35
+ ros.to_h # => { 'fear' => 'is', 'the' => 'mindkiller' }
36
+
37
+ ## Installation
38
+
39
+ Available as a gem in rubygems, the default gem repository.
40
+
41
+ If you use bundler, just throw that in your gemfile :
42
+
43
+ gem 'recursive-open-struct'
44
+
45
+ You may also install the gem manually :
46
+
47
+ gem install recursive-open-struct
48
+
49
+ ## Contributing
50
+
51
+ * Fork the project.
52
+ * Make your feature addition or bug fix.
53
+ * Add tests for your new or changed functionality. Make sure the tests you add
54
+ provide clean and clear explanation of the feature.
55
+ * Send me a pull request. Bonus points for topic branches.
56
+
57
+ ## Copyright
58
+
59
+ Copyright (c) 2009-2016, The Recursive-open-struct developers (given in the
60
+ file AUTHORS.txt). See LICENSE.txt for details.
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler/gem_tasks'
5
+
6
+ require 'rspec/core/rake_task'
7
+ RSpec::Core::RakeTask.new(:spec) do |spec|
8
+ spec.pattern = FileList['spec/**/*_spec.rb']
9
+ end
10
+ namespace :spec do
11
+ if RUBY_VERSION =~ /^1\.8/
12
+ desc "Rspec code coverage (1.8.7)"
13
+ RSpec::Core::RakeTask.new(:coverage) do |spec|
14
+ spec.pattern = 'spec/**/*_spec.rb'
15
+ spec.rcov = true
16
+ end
17
+ else
18
+ desc "Rspec code coverage (1.9+)"
19
+ task :coverage do
20
+ ENV['COVERAGE'] = 'true'
21
+ Rake::Task["spec"].execute
22
+ end
23
+ end
24
+ end
25
+
26
+ require 'rdoc/task'
27
+ Rake::RDocTask.new do |rdoc|
28
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
29
+
30
+ rdoc.rdoc_dir = 'rdoc'
31
+ rdoc.title = "recursive-open-struct #{version}"
32
+ rdoc.rdoc_files.include('README*')
33
+ rdoc.rdoc_files.include('lib/**/*.rb')
34
+ end
35
+
36
+ task :default => :spec
37
+
38
+ task :fix_permissions do
39
+ File.umask 0022
40
+ filelist = `git ls-files`.split("\n")
41
+ FileUtils.chmod 0644, filelist, :verbose => true
42
+ FileUtils.chmod 0755, ['lib','spec'], :verbose => true
43
+ end
44
+
45
+ desc "Update the AUTHORS.txt file"
46
+ task :update_authors do
47
+ authors = `git log --format="%aN <%aE>"|sort -f|uniq`
48
+ File.open('AUTHORS.txt', 'w') do |f|
49
+ f.write("Recursive-open-struct was written by these fine people:\n\n")
50
+ f.write(authors.split("\n").map { |a| "* #{a}" }.join( "\n" ))
51
+ f.write("\n")
52
+ end
53
+ end
54
+
55
+ task :build => [:update_authors, :fix_permissions]
56
+
57
+ desc "Run an interactive pry shell with ros required"
58
+ task :pry do
59
+ sh "pry -I lib -r recursive-open-struct"
60
+ end
@@ -0,0 +1 @@
1
+ require 'recursive_open_struct'
@@ -0,0 +1,130 @@
1
+ require 'ostruct'
2
+ require 'recursive_open_struct/version'
3
+
4
+ require 'recursive_open_struct/debug_inspect'
5
+ require 'recursive_open_struct/deep_dup'
6
+ require 'recursive_open_struct/ruby_19_backport'
7
+
8
+ class RecursiveOpenStruct < OpenStruct
9
+ include Ruby19Backport if RUBY_VERSION =~ /\A1.9/
10
+ include DebugInspect
11
+
12
+ def initialize(hash=nil, args={})
13
+ hash ||= {}
14
+ @recurse_over_arrays = args.fetch(:recurse_over_arrays, false)
15
+ @preserve_original_keys = args.fetch(:preserve_original_keys, false)
16
+ @deep_dup = DeepDup.new(
17
+ recurse_over_arrays: @recurse_over_arrays,
18
+ preserve_original_keys: @preserve_original_keys
19
+ )
20
+
21
+ @table = args.fetch(:mutate_input_hash, false) ? hash : @deep_dup.call(hash)
22
+
23
+ @sub_elements = {}
24
+ end
25
+
26
+ def initialize_copy(orig)
27
+ super
28
+
29
+ # deep copy the table to separate the two objects
30
+ @table = @deep_dup.call(orig.instance_variable_get(:@table))
31
+ # Forget any memoized sub-elements
32
+ @sub_elements = {}
33
+ end
34
+
35
+ def to_h
36
+ @deep_dup.call(@table)
37
+ end
38
+
39
+ alias_method :to_hash, :to_h
40
+
41
+ def [](name)
42
+ public_send(name)
43
+ end
44
+
45
+ # Makes sure ROS responds as expected on #respond_to? and #method requests
46
+ def respond_to_missing?(mid, include_private = false)
47
+ mname = _get_key_from_table_(mid.to_s.chomp('=').chomp('_as_a_hash'))
48
+ @table.key?(mname) || super
49
+ end
50
+
51
+ # Adapted implementation of method_missing to accomodate the differences between ROS and OS.
52
+ def method_missing(mid, *args)
53
+ len = args.length
54
+ if mid =~ /^(.*)=$/
55
+ if len != 1
56
+ raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
57
+ end
58
+ modifiable[new_ostruct_member($1.to_sym)] = args[0]
59
+ elsif len == 0
60
+ key = mid
61
+ key = $1 if key =~ /^(.*)_as_a_hash$/
62
+ if @table.key?(_get_key_from_table_(key))
63
+ new_ostruct_member(key)
64
+ send(mid)
65
+ end
66
+ else
67
+ err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
68
+ err.set_backtrace caller(1)
69
+ raise err
70
+ end
71
+ end
72
+
73
+ def new_ostruct_member(name)
74
+ key_name = _get_key_from_table_ name
75
+ unless self.methods.include?(name.to_sym)
76
+ class << self; self; end.class_eval do
77
+ define_method(name) do
78
+ v = @table[key_name]
79
+ if v.is_a?(Hash)
80
+ @sub_elements[key_name] ||= self.class.new(
81
+ v,
82
+ recurse_over_arrays: @recurse_over_arrays,
83
+ preserve_original_keys: @preserve_original_keys,
84
+ mutate_input_hash: true
85
+ )
86
+ elsif v.is_a?(Array) and @recurse_over_arrays
87
+ @sub_elements[key_name] ||= recurse_over_array(v)
88
+ @sub_elements[key_name] = recurse_over_array(@sub_elements[key_name])
89
+ else
90
+ v
91
+ end
92
+ end
93
+ define_method("#{name}=") do |x|
94
+ @sub_elements.delete(key_name)
95
+ modifiable[key_name] = x
96
+ end
97
+ define_method("#{name}_as_a_hash") { @table[key_name] }
98
+ end
99
+ end
100
+ key_name
101
+ end
102
+
103
+ def delete_field(name)
104
+ sym = _get_key_from_table_(name)
105
+ singleton_class.__send__(:remove_method, sym, "#{sym}=") rescue NoMethodError # ignore if methods not yet generated.
106
+ @sub_elements.delete sym
107
+ @table.delete sym
108
+ end
109
+
110
+ private
111
+
112
+ def _get_key_from_table_(name)
113
+ return name.to_s if @table.has_key?(name.to_s)
114
+ return name.to_sym if @table.has_key?(name.to_sym)
115
+ name
116
+ end
117
+
118
+ def recurse_over_array(array)
119
+ array.each_with_index do |a, i|
120
+ if a.is_a? Hash
121
+ array[i] = self.class.new(a, :recurse_over_arrays => true,
122
+ :mutate_input_hash => true, :preserve_original_keys => @preserve_original_keys)
123
+ elsif a.is_a? Array
124
+ array[i] = recurse_over_array a
125
+ end
126
+ end
127
+ array
128
+ end
129
+
130
+ end