mighty_struct 0.1.2 → 0.1.4

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: e1befffda2350b4119620bc5a265ec2e7dfa61eb
4
- data.tar.gz: 1f9d05937b898767975ce10a400e4f16f69c7a73
3
+ metadata.gz: f8d7b9936e89b506c81ae023b4f503b838670c6a
4
+ data.tar.gz: d377473551801d74b6aeafa3a2b008c77690c756
5
5
  SHA512:
6
- metadata.gz: 809f0eb22a097d19788102ae76d90289c88d8faa76c3a9cefdfae60142aae3aff6c9f4118789ee7f45738af75a09a32a1e0356ea91789bff95a8d2030107985f
7
- data.tar.gz: 81da6ad10ef7d667c8b66c1f6c99a44f3679c1a7371e6ee3ad600bf941a4b38848a049d133242708fd4c249ee672d68fb6a2fa56af70ea3df78315387ca67360
6
+ metadata.gz: 894c82f523a88a02172d576649c41282c7620fde4e57a91b0011139c8d28e9ddd79ea7535b3a7c145fbaaa2f81f2ea853720471cca6a04e21c282e798a5960f2
7
+ data.tar.gz: 8e5fe24e3cb830edacc15af24e7dd2e8859cd1dc8a4c2171c6d4e44e187a2b73b6b71e39ebe0f36d203bf092b2622e925a47f5fa76645960c808cfef7141a2c7
data/.codeclimate.yml ADDED
@@ -0,0 +1,2 @@
1
+ exclude_paths:
2
+ - "benchmark/*"
data/.travis.yml CHANGED
@@ -1,5 +1,9 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "2.0"
4
- - "2.1"
5
- - "2.2"
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.0
6
+ - 2.2.0
7
+ - jruby-1.7
8
+ - jruby-9.0.0.0.pre2
9
+ - rbx-2.5
data/Gemfile CHANGED
@@ -3,9 +3,8 @@ source "https://rubygems.org"
3
3
  # Specify your gem's dependencies in your gemspec
4
4
  gemspec
5
5
 
6
- if !ENV["CI"]
6
+ if !ENV["CI"] && RUBY_ENGINE == "ruby"
7
7
  group :development do
8
- gem "hashdiff"
9
8
  gem "pry", "~> 0.9.12.6"
10
9
  gem "pry-byebug", "<= 1.3.2"
11
10
  gem "pry-rescue", "~> 1.4.1", github: "ConradIrwin/pry-rescue", branch: :master
data/README.md CHANGED
@@ -1,28 +1,78 @@
1
1
  # MightyStruct
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/mighty_struct`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ [![Build Status](https://travis-ci.org/msievers/mighty_struct.svg)](https://travis-ci.org/msievers/mighty_struct)
4
+ [![Test Coverage](https://codeclimate.com/github/msievers/mighty_struct/badges/coverage.svg)](https://codeclimate.com/github/msievers/mighty_struct/coverage)
5
+ [![Code Climate](https://codeclimate.com/github/msievers/mighty_struct/badges/gpa.svg)](https://codeclimate.com/github/msievers/mighty_struct)
6
+ [![Dependency Status](https://gemnasium.com/msievers/mighty_struct.svg)](https://gemnasium.com/msievers/mighty_struct)
4
7
 
5
- TODO: Delete this and the text above, and describe your gem
8
+ `MightyStruct` is an object wrapper which gives deep method access to properties. It combines beneficial features from functionally related projects like `OpenStruct` and `Hashie::Mash` into an non-inversive, transparant decorator like object wrapper.
6
9
 
7
- ## Installation
10
+ ## Key features
8
11
 
9
- Add this line to your application's Gemfile:
12
+ * wraps any object that is an `Enumerable` (e.g `Array` or `Hash`)
13
+ * creates method accessors for any object that additionally responds to `:keys` (e.g. `Hash`)
14
+ * deep method access to object properties
15
+ * property accessors are implemented via methods, not `method_missing`
16
+ * as a result tab completion in pry works
17
+ * dispite property accessors, the namespace of wrapped objects isn't touched
18
+ * all method calls which don't hit a property accessor are dispatched to the wrapped object
19
+ * results are again wrapped to instances of MightyStruct if possible
20
+ * the wrapped object can be retrieved at any time using `MightyStruct.to_object(obj)`
21
+
22
+ ## Example
10
23
 
11
24
  ```ruby
12
- gem 'mighty_struct'
25
+ require "mighty_struct"
26
+
27
+ hash = {
28
+ a: [
29
+ { b: 1 },
30
+ { b: 2 },
31
+ ],
32
+ }
33
+
34
+ # create it from some hash or array
35
+ mighty_struct = MightyStruct.new(hash)
36
+
37
+ # access deeply nested properties
38
+ mighty_struct.a[0].b # => 1
39
+
40
+ # call methods transparently on the wrapped objects
41
+ mighty_struct.a.last.b # => 2
42
+
43
+ # get back the original object ... look ma', it's still the same hash
44
+ MightyStruct.to_object(mighty_struct).eql?(hash) # => true
13
45
  ```
14
46
 
15
- And then execute:
47
+ Or play with it on your own. It's just one command (line) away.
48
+
49
+ ```bash
50
+ git clone https://github.com/msievers/mighty_struct.git && cd mighty_struct && bundle && bin/console
51
+ ```
52
+
53
+ ## Another of this "method invocation" hashes? Really?!
54
+
55
+ Before I started coding this, I tried the following three alternatives
56
+
57
+ * `OpenStruct`
58
+ * `recursive-open-struct`
59
+ * `Hashie::Mash`
16
60
 
17
- $ bundle
61
+ But neither of them provided everything I wanted.
18
62
 
19
- Or install it yourself as:
63
+ | MightyStruct | OpenStruct | recursive-open-struct | Hashie::Mash
64
+ --- | :----------: | :--------: | :-------------------: | :----------:
65
+ deep method access | :heavy_check_mark: | :heavy_multiplication_x: | (:heavy_check_mark:) | :heavy_check_mark:
66
+ real method accessors | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x:
67
+ works without object dupping | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x:
68
+ transparent method dispatching | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x:
69
+ original object retrieval | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x:
20
70
 
21
- $ gem install mighty_struct
71
+ ## Why are real methods as property accessors cool?
22
72
 
23
- ## Usage
73
+ Method accessors for object properties can either be implemented via `method_missing` or by defining (singleton) methods. The benefit of real methods is, that if you are using a debugger (e.g. `pry`), you can use tab completion to discover methods defined on a object. This does not work for `method_missing` based accessors.
24
74
 
25
- TODO: Write usage instructions here
75
+ With real method accessors in place, playing with a `mighty_struct` within `pry` just feels like working within a shell.
26
76
 
27
77
  ## Development
28
78
 
@@ -32,7 +82,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
82
 
33
83
  ## Contributing
34
84
 
35
- 1. Fork it ( https://github.com/[my-github-username]/mighty_struct/fork )
85
+ 1. Fork it ( https://github.com/msievers/mighty_struct/fork )
36
86
  2. Create your feature branch (`git checkout -b my-new-feature`)
37
87
  3. Commit your changes (`git commit -am 'Add some feature'`)
38
88
  4. Push to the branch (`git push origin my-new-feature`)
data/Rakefile CHANGED
@@ -6,9 +6,7 @@ RSpec::Core::RakeTask.new(:spec)
6
6
  task :default => :spec
7
7
 
8
8
  task :benchmark do
9
- require_relative "./benchmark/joffrey/mab_document"
10
- require_relative "./benchmark/joffrey/mab_xml_parser"
9
+ require_relative "./benchmark/mighty_struct/mighty_struct_versus_others"
11
10
 
12
- #Benchmark::Joffrey::MabDocument.new.call
13
- Benchmark::Joffrey::MabXmlParser.new.call
11
+ Benchmark::MightyStruct::MightyStructVersusOthers.new.call
14
12
  end
@@ -0,0 +1,4 @@
1
+ require "benchmark/ips"
2
+
3
+ class Benchmark::MightyStruct
4
+ end
@@ -0,0 +1,60 @@
1
+ require "hashie/mash"
2
+ require "mighty_struct"
3
+ require "pry"
4
+ require_relative "../mighty_struct"
5
+
6
+ class Benchmark::MightyStruct::MightyStructVersusOthers
7
+ def call
8
+ hash = {
9
+ a: 1,
10
+ b: {
11
+ c: 2,
12
+ "d" => 3,
13
+ e: [
14
+ {
15
+ f: 4
16
+ }
17
+ ]
18
+ }
19
+ }
20
+
21
+ puts "\n"
22
+
23
+ Benchmark.ips do |x|
24
+ puts "Hashie::Mash.new(hash)"
25
+ puts "MightyStruct.new(hash)"
26
+ puts "OpenStruct.new(hash)"
27
+ puts "\n"
28
+
29
+ x.report("Hashie::Mash") { Hashie::Mash.new(hash) }
30
+ x.report("MightyStruct") { MightyStruct.new(hash) }
31
+ x.report("OpenStruct") { OpenStruct.new(hash) }
32
+
33
+ x.compare!
34
+ end
35
+
36
+ [:enabled, :disabled].each do |_caching_mode|
37
+ puts "Hashie::Mash.new(hash).b.c"
38
+ puts "MightyStruct.new(hash, caching: :#{_caching_mode}).b.c"
39
+ puts "OpenStruct.new(hash).b.c"
40
+ puts "\n"
41
+
42
+ Benchmark.ips do |x|
43
+ hashie_mash = Hashie::Mash.new(hash)
44
+ mighty_struct = MightyStruct.new(hash, caching: _caching_mode)
45
+ open_struct = OpenStruct.new(hash)
46
+ open_struct.b = OpenStruct.new(open_struct.b)
47
+
48
+ if hashie_mash.b.c != hash[:b][:c] || mighty_struct.b.c != hash[:b][:c] || open_struct.b.c != hash[:b][:c]
49
+ raise
50
+ end
51
+
52
+ x.report("Hashie::Mash") { hashie_mash.b.c }
53
+ x.report("MightyStruct") { mighty_struct.b.c }
54
+ x.report("OpenStruct") { open_struct.b.c }
55
+
56
+ x.compare!
57
+ end
58
+ end
59
+ end
60
+ end
data/bin/console CHANGED
@@ -6,9 +6,10 @@ require "mighty_struct"
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
9
+ begin
10
+ require "pry"
11
+ Pry.start
12
+ rescue LoadError
13
+ require "irb"
14
+ IRB.start
15
+ end
data/lib/mighty_struct.rb CHANGED
@@ -1,29 +1,36 @@
1
1
  require "mighty_struct/version"
2
2
 
3
3
  class MightyStruct
4
- def self.define_property_accessors!(mighty_struct, object)
5
- if object.is_a?(Hash)
6
- object.keys.each do |_key|
7
- class_eval <<-EORUBY, __FILE__, __LINE__ + 1
8
- def #{_key}
9
- value = @object[#{_key.is_a?(Symbol) ? ':' << _key.to_s : '"' << _key << '"'}]
10
- self.class.new?(value) ? self.class.new(value) : value
11
- end
12
- EORUBY
13
- end
14
- end
4
+ def self.new?(object)
5
+ object.is_a?(Enumerable)
15
6
  end
16
7
 
17
- def self.new?(object)
18
- object.is_a?(Array) || object.is_a?(Hash)
8
+ # in order not to pollute the instance's method namespace this is a class method
9
+ def self.to_object(object)
10
+ object.is_a?(self) ? object.instance_variable_get(:@object) : object
19
11
  end
20
12
 
21
- def initialize(object)
13
+ def initialize(object, options = {})
22
14
  unless self.class.new?(object)
23
15
  raise ArgumentError.new("Cannot create a an instance of #{self.class} for the given object!")
24
16
  end
25
17
 
26
- self.class.define_property_accessors!(self, @object = object)
18
+ @cache = {}
19
+ @cache_mode = options[:caching] || :enabled
20
+
21
+ if (@object = object).respond_to?(:keys)
22
+ object.keys.each do |_key|
23
+ unless respond_to?(_key)
24
+ define_singleton_method(_key) do
25
+ if @cache_mode == :disabled
26
+ self.class.new?(value = @object[_key]) ? self.class.new(value) : value
27
+ else
28
+ @cache[_key] ||= self.class.new?(value = @object[_key]) ? self.class.new(value) : value
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
27
34
  end
28
35
 
29
36
  #
@@ -31,6 +38,7 @@ class MightyStruct
31
38
  #
32
39
  def method_missing(method_name, *arguments, &block)
33
40
  if @object.respond_to?(method_name)
41
+ @cache.clear if @cache_mode == :smart # clear the properties cache if we are smart
34
42
  result = @object.send(method_name, *arguments, &block)
35
43
 
36
44
  # ensure that results of called methods are mighty structs again
@@ -1,3 +1,3 @@
1
1
  class MightyStruct
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.add_development_dependency "benchmark-ips"
19
19
  spec.add_development_dependency "bundler", ">= 1.3"
20
+ spec.add_development_dependency "hashie"
20
21
  spec.add_development_dependency "rake"
21
22
  spec.add_development_dependency "rspec", ">= 3.0.0", "< 4.0.0"
22
23
  spec.add_development_dependency "simplecov", ">= 0.8.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mighty_struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Sievers
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-05-20 00:00:00.000000000 Z
11
+ date: 2015-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: hashie
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -92,12 +106,15 @@ executables: []
92
106
  extensions: []
93
107
  extra_rdoc_files: []
94
108
  files:
109
+ - ".codeclimate.yml"
95
110
  - ".gitignore"
96
111
  - ".rspec"
97
112
  - ".travis.yml"
98
113
  - Gemfile
99
114
  - README.md
100
115
  - Rakefile
116
+ - benchmark/mighty_struct.rb
117
+ - benchmark/mighty_struct/mighty_struct_versus_others.rb
101
118
  - bin/console
102
119
  - bin/setup
103
120
  - lib/mighty_struct.rb
@@ -122,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
139
  version: '0'
123
140
  requirements: []
124
141
  rubyforge_project:
125
- rubygems_version: 2.4.6
142
+ rubygems_version: 2.4.7
126
143
  signing_key:
127
144
  specification_version: 4
128
145
  summary: A mighty struct which combines OpenStruct like method access with reasonable