mighty_struct 0.1.2 → 0.1.4
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 +4 -4
- data/.codeclimate.yml +2 -0
- data/.travis.yml +7 -3
- data/Gemfile +1 -2
- data/README.md +62 -12
- data/Rakefile +2 -4
- data/benchmark/mighty_struct.rb +4 -0
- data/benchmark/mighty_struct/mighty_struct_versus_others.rb +60 -0
- data/bin/console +7 -6
- data/lib/mighty_struct.rb +23 -15
- data/lib/mighty_struct/version.rb +1 -1
- data/mighty_struct.gemspec +1 -0
- metadata +20 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f8d7b9936e89b506c81ae023b4f503b838670c6a
         | 
| 4 | 
            +
              data.tar.gz: d377473551801d74b6aeafa3a2b008c77690c756
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 894c82f523a88a02172d576649c41282c7620fde4e57a91b0011139c8d28e9ddd79ea7535b3a7c145fbaaa2f81f2ea853720471cca6a04e21c282e798a5960f2
         | 
| 7 | 
            +
              data.tar.gz: 8e5fe24e3cb830edacc15af24e7dd2e8859cd1dc8a4c2171c6d4e44e187a2b73b6b71e39ebe0f36d203bf092b2622e925a47f5fa76645960c808cfef7141a2c7
         | 
    
        data/.codeclimate.yml
    ADDED
    
    
    
        data/.travis.yml
    CHANGED
    
    
    
        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 | 
            -
             | 
| 3 | 
            +
            [](https://travis-ci.org/msievers/mighty_struct)
         | 
| 4 | 
            +
            [](https://codeclimate.com/github/msievers/mighty_struct/coverage)
         | 
| 5 | 
            +
            [](https://codeclimate.com/github/msievers/mighty_struct)
         | 
| 6 | 
            +
            [](https://gemnasium.com/msievers/mighty_struct)
         | 
| 4 7 |  | 
| 5 | 
            -
             | 
| 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 | 
            -
            ##  | 
| 10 | 
            +
            ## Key features
         | 
| 8 11 |  | 
| 9 | 
            -
             | 
| 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 | 
            -
             | 
| 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 | 
            -
             | 
| 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 | 
            -
             | 
| 61 | 
            +
            But neither of them provided everything I wanted.
         | 
| 18 62 |  | 
| 19 | 
            -
             | 
| 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 | 
            -
             | 
| 71 | 
            +
            ## Why are real methods as property accessors cool?
         | 
| 22 72 |  | 
| 23 | 
            -
             | 
| 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 | 
            -
             | 
| 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/ | 
| 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/ | 
| 10 | 
            -
              require_relative "./benchmark/joffrey/mab_xml_parser"
         | 
| 9 | 
            +
              require_relative "./benchmark/mighty_struct/mighty_struct_versus_others"
         | 
| 11 10 |  | 
| 12 | 
            -
               | 
| 13 | 
            -
              Benchmark::Joffrey::MabXmlParser.new.call
         | 
| 11 | 
            +
              Benchmark::MightyStruct::MightyStructVersusOthers.new.call
         | 
| 14 12 | 
             
            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 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 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. | 
| 5 | 
            -
                 | 
| 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 | 
            -
               | 
| 18 | 
            -
             | 
| 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 | 
            -
                 | 
| 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
         | 
    
        data/mighty_struct.gemspec
    CHANGED
    
    | @@ -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. | 
| 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- | 
| 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. | 
| 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
         |