collapsium 0.4.1 → 0.5.0
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/Gemfile.lock +8 -8
 - data/collapsium.gemspec +2 -2
 - data/lib/collapsium/environment_override.rb +65 -52
 - data/lib/collapsium/pathed_access.rb +54 -89
 - data/lib/collapsium/support/array_methods.rb +48 -0
 - data/lib/collapsium/support/methods.rb +69 -5
 - data/lib/collapsium/support/path_components.rb +95 -0
 - data/lib/collapsium/version.rb +1 -1
 - data/lib/collapsium/viral_capabilities.rb +206 -40
 - data/spec/environment_override_spec.rb +43 -18
 - data/spec/pathed_access_spec.rb +96 -31
 - data/spec/support_methods_spec.rb +247 -5
 - data/spec/support_path_components.rb +85 -0
 - data/spec/viral_capabilities_spec.rb +42 -15
 - metadata +10 -6
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: c4eb75d59a4fd999a789ee4fb811263dea86b493
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 15a3e7ff204d3268112e41a565d6d441d60db873
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 31d5e290424e9e75eda116508351e2ae7ff3873ba977257140bf1112532278f4eae00590e9974b351d84afa89b1e1943d7ed4b4f74705c2ae54d6538b948b71f
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 395b15971c754dea2eea60d7ebd601691f02214e7eeb97fa25281626b84cdaf6b4ecbb40585ebbfd8daa3914aa770f28856c81de8d7543a3e43ce15b8d4bc5a2
         
     | 
    
        data/Gemfile.lock
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            PATH
         
     | 
| 
       2 
2 
     | 
    
         
             
              remote: .
         
     | 
| 
       3 
3 
     | 
    
         
             
              specs:
         
     | 
| 
       4 
     | 
    
         
            -
                collapsium (0. 
     | 
| 
      
 4 
     | 
    
         
            +
                collapsium (0.5.0)
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            GEM
         
     | 
| 
       7 
7 
     | 
    
         
             
              remote: https://rubygems.org/
         
     | 
| 
         @@ -12,16 +12,16 @@ GEM 
     | 
|
| 
       12 
12 
     | 
    
         
             
                diff-lcs (1.2.5)
         
     | 
| 
       13 
13 
     | 
    
         
             
                docile (1.1.5)
         
     | 
| 
       14 
14 
     | 
    
         
             
                json (2.0.2)
         
     | 
| 
       15 
     | 
    
         
            -
                parser (2.3.1. 
     | 
| 
      
 15 
     | 
    
         
            +
                parser (2.3.1.4)
         
     | 
| 
       16 
16 
     | 
    
         
             
                  ast (~> 2.2)
         
     | 
| 
       17 
17 
     | 
    
         
             
                powerpack (0.1.1)
         
     | 
| 
       18 
18 
     | 
    
         
             
                rainbow (2.1.0)
         
     | 
| 
       19 
     | 
    
         
            -
                rake (11. 
     | 
| 
      
 19 
     | 
    
         
            +
                rake (11.3.0)
         
     | 
| 
       20 
20 
     | 
    
         
             
                rspec (3.5.0)
         
     | 
| 
       21 
21 
     | 
    
         
             
                  rspec-core (~> 3.5.0)
         
     | 
| 
       22 
22 
     | 
    
         
             
                  rspec-expectations (~> 3.5.0)
         
     | 
| 
       23 
23 
     | 
    
         
             
                  rspec-mocks (~> 3.5.0)
         
     | 
| 
       24 
     | 
    
         
            -
                rspec-core (3.5. 
     | 
| 
      
 24 
     | 
    
         
            +
                rspec-core (3.5.4)
         
     | 
| 
       25 
25 
     | 
    
         
             
                  rspec-support (~> 3.5.0)
         
     | 
| 
       26 
26 
     | 
    
         
             
                rspec-expectations (3.5.0)
         
     | 
| 
       27 
27 
     | 
    
         
             
                  diff-lcs (>= 1.2.0, < 2.0)
         
     | 
| 
         @@ -30,7 +30,7 @@ GEM 
     | 
|
| 
       30 
30 
     | 
    
         
             
                  diff-lcs (>= 1.2.0, < 2.0)
         
     | 
| 
       31 
31 
     | 
    
         
             
                  rspec-support (~> 3.5.0)
         
     | 
| 
       32 
32 
     | 
    
         
             
                rspec-support (3.5.0)
         
     | 
| 
       33 
     | 
    
         
            -
                rubocop (0. 
     | 
| 
      
 33 
     | 
    
         
            +
                rubocop (0.44.1)
         
     | 
| 
       34 
34 
     | 
    
         
             
                  parser (>= 2.3.1.1, < 3.0)
         
     | 
| 
       35 
35 
     | 
    
         
             
                  powerpack (~> 0.1)
         
     | 
| 
       36 
36 
     | 
    
         
             
                  rainbow (>= 1.99.1, < 3.0)
         
     | 
| 
         @@ -42,7 +42,7 @@ GEM 
     | 
|
| 
       42 
42 
     | 
    
         
             
                  json (>= 1.8, < 3)
         
     | 
| 
       43 
43 
     | 
    
         
             
                  simplecov-html (~> 0.10.0)
         
     | 
| 
       44 
44 
     | 
    
         
             
                simplecov-html (0.10.0)
         
     | 
| 
       45 
     | 
    
         
            -
                unicode-display_width (1.1. 
     | 
| 
      
 45 
     | 
    
         
            +
                unicode-display_width (1.1.1)
         
     | 
| 
       46 
46 
     | 
    
         
             
                yard (0.9.5)
         
     | 
| 
       47 
47 
     | 
    
         | 
| 
       48 
48 
     | 
    
         
             
            PLATFORMS
         
     | 
| 
         @@ -52,9 +52,9 @@ DEPENDENCIES 
     | 
|
| 
       52 
52 
     | 
    
         
             
              bundler (~> 1.12)
         
     | 
| 
       53 
53 
     | 
    
         
             
              codeclimate-test-reporter
         
     | 
| 
       54 
54 
     | 
    
         
             
              collapsium!
         
     | 
| 
       55 
     | 
    
         
            -
              rake (~> 11. 
     | 
| 
      
 55 
     | 
    
         
            +
              rake (~> 11.3)
         
     | 
| 
       56 
56 
     | 
    
         
             
              rspec (~> 3.5)
         
     | 
| 
       57 
     | 
    
         
            -
              rubocop (~> 0. 
     | 
| 
      
 57 
     | 
    
         
            +
              rubocop (~> 0.44)
         
     | 
| 
       58 
58 
     | 
    
         
             
              simplecov (~> 0.12)
         
     | 
| 
       59 
59 
     | 
    
         
             
              yard (~> 0.9)
         
     | 
| 
       60 
60 
     | 
    
         | 
    
        data/collapsium.gemspec
    CHANGED
    
    | 
         @@ -35,8 +35,8 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       35 
35 
     | 
    
         
             
              spec.required_ruby_version = '>= 2.0'
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
              spec.add_development_dependency "bundler", "~> 1.12"
         
     | 
| 
       38 
     | 
    
         
            -
              spec.add_development_dependency "rubocop", "~> 0. 
     | 
| 
       39 
     | 
    
         
            -
              spec.add_development_dependency "rake", "~> 11. 
     | 
| 
      
 38 
     | 
    
         
            +
              spec.add_development_dependency "rubocop", "~> 0.44"
         
     | 
| 
      
 39 
     | 
    
         
            +
              spec.add_development_dependency "rake", "~> 11.3"
         
     | 
| 
       40 
40 
     | 
    
         
             
              spec.add_development_dependency "rspec", "~> 3.5"
         
     | 
| 
       41 
41 
     | 
    
         
             
              spec.add_development_dependency "simplecov", "~> 0.12"
         
     | 
| 
       42 
42 
     | 
    
         
             
              spec.add_development_dependency "yard", "~> 0.9"
         
     | 
| 
         @@ -39,6 +39,7 @@ module Collapsium 
     | 
|
| 
       39 
39 
     | 
    
         
             
                # wrap accessor methods.
         
     | 
| 
       40 
40 
     | 
    
         
             
                class << self
         
     | 
| 
       41 
41 
     | 
    
         
             
                  include ::Collapsium::Support::HashMethods
         
     | 
| 
      
 42 
     | 
    
         
            +
                  include ::Collapsium::Support::ArrayMethods
         
     | 
| 
       42 
43 
     | 
    
         
             
                  include ::Collapsium::Support::Methods
         
     | 
| 
       43 
44 
     | 
    
         | 
| 
       44 
45 
     | 
    
         
             
                  ##
         
     | 
| 
         @@ -62,6 +63,54 @@ module Collapsium 
     | 
|
| 
       62 
63 
     | 
    
         
             
                    # supported, we'll try environment variables of the path, starting
         
     | 
| 
       63 
64 
     | 
    
         
             
                    # with the full qualified path and ending with just the last key
         
     | 
| 
       64 
65 
     | 
    
         
             
                    # component.
         
     | 
| 
      
 66 
     | 
    
         
            +
                    env_keys = EnvironmentOverride.environment_variables_for_key(receiver, key)
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    # When we have the keys (in priority order), try to see if the
         
     | 
| 
      
 69 
     | 
    
         
            +
                    # environment yields something useful.
         
     | 
| 
      
 70 
     | 
    
         
            +
                    value = EnvironmentOverride.override_value(env_keys, receiver, key)
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    if not value.nil?
         
     | 
| 
      
 73 
     | 
    
         
            +
                      # We can't just return the value, because that doesn't respect the
         
     | 
| 
      
 74 
     | 
    
         
            +
                      # method being called. We also can't store the value, because that
         
     | 
| 
      
 75 
     | 
    
         
            +
                      # would not reset the Hash after the environment variable was
         
     | 
| 
      
 76 
     | 
    
         
            +
                      # cleared.
         
     | 
| 
      
 77 
     | 
    
         
            +
                      #
         
     | 
| 
      
 78 
     | 
    
         
            +
                      # We can deal with this by duplicating the receiver, writing the value
         
     | 
| 
      
 79 
     | 
    
         
            +
                      # we found into the appropriate key, and then sending the
         
     | 
| 
      
 80 
     | 
    
         
            +
                      # wrapped_method to the duplicate.
         
     | 
| 
      
 81 
     | 
    
         
            +
                      double = receiver.recursive_dup
         
     | 
| 
      
 82 
     | 
    
         
            +
                      double[key] = value
         
     | 
| 
      
 83 
     | 
    
         
            +
                      meth = double.method(wrapped_method.name)
         
     | 
| 
      
 84 
     | 
    
         
            +
                      next meth.call(*args, &block)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                    # Otherwise, fall back on the super method.
         
     | 
| 
      
 88 
     | 
    
         
            +
                    next wrapped_method.call(*args, &block)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end.freeze # proc
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  def included(base)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    enhance(base)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                  def extended(base)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    enhance(base)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  def prepended(base)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    enhance(base)
         
     | 
| 
      
 101 
     | 
    
         
            +
                  end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                  def enhance(base)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    # Make the capabilities of classes using EnvironmentOverride viral.
         
     | 
| 
      
 105 
     | 
    
         
            +
                    base.extend(ViralCapabilities)
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    # Wrap read accessor functions to deal with paths
         
     | 
| 
      
 108 
     | 
    
         
            +
                    (INDEXED_READ_METHODS + KEYED_READ_METHODS).each do |method|
         
     | 
| 
      
 109 
     | 
    
         
            +
                      wrap_method(base, method, raise_on_missing: false, &ENV_ACCESS_READER)
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  def environment_variables_for_key(receiver, key)
         
     | 
| 
       65 
114 
     | 
    
         
             
                    env_keys = []
         
     | 
| 
       66 
115 
     | 
    
         
             
                    if receiver.respond_to?(:path_prefix)
         
     | 
| 
       67 
116 
     | 
    
         | 
| 
         @@ -92,14 +141,16 @@ module Collapsium 
     | 
|
| 
       92 
141 
     | 
    
         
             
                    else
         
     | 
| 
       93 
142 
     | 
    
         
             
                      env_keys = [key.to_s]
         
     | 
| 
       94 
143 
     | 
    
         
             
                    end
         
     | 
| 
       95 
     | 
    
         
            -
                    env_keys.map! { |k|  
     | 
| 
      
 144 
     | 
    
         
            +
                    env_keys.map! { |k| key_to_env(k) }
         
     | 
| 
       96 
145 
     | 
    
         
             
                    env_keys.select! { |k| not k.empty? }
         
     | 
| 
       97 
146 
     | 
    
         
             
                    env_keys.uniq!
         
     | 
| 
       98 
147 
     | 
    
         | 
| 
       99 
     | 
    
         
            -
                     
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
      
 148 
     | 
    
         
            +
                    return env_keys
         
     | 
| 
      
 149 
     | 
    
         
            +
                  end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                  def override_value(variables, receiver, key)
         
     | 
| 
       101 
152 
     | 
    
         
             
                    value = nil
         
     | 
| 
       102 
     | 
    
         
            -
                     
     | 
| 
      
 153 
     | 
    
         
            +
                    variables.each do |env_key|
         
     | 
| 
       103 
154 
     | 
    
         
             
                      # Grab the environment value; skip if there's nothing there.
         
     | 
| 
       104 
155 
     | 
    
         
             
                      env_value = ENV[env_key]
         
     | 
| 
       105 
156 
     | 
    
         
             
                      if env_value.nil?
         
     | 
| 
         @@ -131,60 +182,22 @@ module Collapsium 
     | 
|
| 
       131 
182 
     | 
    
         
             
                      break
         
     | 
| 
       132 
183 
     | 
    
         
             
                    end
         
     | 
| 
       133 
184 
     | 
    
         | 
| 
       134 
     | 
    
         
            -
                     
     | 
| 
       135 
     | 
    
         
            -
                      # We can't just return the value, because that doesn't respect the
         
     | 
| 
       136 
     | 
    
         
            -
                      # method being called. We also can't store the value, because that
         
     | 
| 
       137 
     | 
    
         
            -
                      # would not reset the Hash after the environment variable was
         
     | 
| 
       138 
     | 
    
         
            -
                      # cleared.
         
     | 
| 
       139 
     | 
    
         
            -
                      #
         
     | 
| 
       140 
     | 
    
         
            -
                      # We can deal with this by duplicating the receiver, writing the value
         
     | 
| 
       141 
     | 
    
         
            -
                      # we found into the appropriate key, and then sending the
         
     | 
| 
       142 
     | 
    
         
            -
                      # wrapped_method to the duplicate.
         
     | 
| 
       143 
     | 
    
         
            -
                      double = receiver.recursive_dup
         
     | 
| 
       144 
     | 
    
         
            -
                      double[key] = value
         
     | 
| 
       145 
     | 
    
         
            -
                      meth = double.method(wrapped_method.name)
         
     | 
| 
       146 
     | 
    
         
            -
                      next meth.call(*args, &block)
         
     | 
| 
       147 
     | 
    
         
            -
                    end
         
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
                    # Otherwise, fall back on the super method.
         
     | 
| 
       150 
     | 
    
         
            -
                    next wrapped_method.call(*args, &block)
         
     | 
| 
       151 
     | 
    
         
            -
                  end.freeze # proc
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                  def included(base)
         
     | 
| 
       154 
     | 
    
         
            -
                    enhance(base)
         
     | 
| 
      
 185 
     | 
    
         
            +
                    return value
         
     | 
| 
       155 
186 
     | 
    
         
             
                  end
         
     | 
| 
       156 
187 
     | 
    
         | 
| 
       157 
     | 
    
         
            -
                  def  
     | 
| 
       158 
     | 
    
         
            -
                     
     | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
      
 188 
     | 
    
         
            +
                  def key_to_env(key)
         
     | 
| 
      
 189 
     | 
    
         
            +
                    # First, convert to upper case
         
     | 
| 
      
 190 
     | 
    
         
            +
                    env_key = key.upcase
         
     | 
| 
       160 
191 
     | 
    
         | 
| 
       161 
     | 
    
         
            -
             
     | 
| 
       162 
     | 
    
         
            -
                     
     | 
| 
       163 
     | 
    
         
            -
             
     | 
| 
      
 192 
     | 
    
         
            +
                    # Next, replace non-alphanumeric characters to underscore. This also
         
     | 
| 
      
 193 
     | 
    
         
            +
                    # collapses them into a single undescore.
         
     | 
| 
      
 194 
     | 
    
         
            +
                    env_key.gsub!(/[^[:alnum:]]+/, '_')
         
     | 
| 
       164 
195 
     | 
    
         | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
                     
     | 
| 
       167 
     | 
    
         
            -
                    base.extend(ViralCapabilities)
         
     | 
| 
      
 196 
     | 
    
         
            +
                    # Strip leading and trailing underscores.
         
     | 
| 
      
 197 
     | 
    
         
            +
                    env_key.gsub!(/^_*(.*?)_*$/, '\1')
         
     | 
| 
       168 
198 
     | 
    
         | 
| 
       169 
     | 
    
         
            -
                     
     | 
| 
       170 
     | 
    
         
            -
                    KEYED_READ_METHODS.each do |method|
         
     | 
| 
       171 
     | 
    
         
            -
                      wrap_method(base, method, &ENV_ACCESS_READER)
         
     | 
| 
       172 
     | 
    
         
            -
                    end
         
     | 
| 
      
 199 
     | 
    
         
            +
                    return env_key
         
     | 
| 
       173 
200 
     | 
    
         
             
                  end
         
     | 
| 
       174 
201 
     | 
    
         
             
                end # class << self
         
     | 
| 
       175 
     | 
    
         
            -
             
     | 
| 
       176 
     | 
    
         
            -
                def key_to_env(key)
         
     | 
| 
       177 
     | 
    
         
            -
                  # First, convert to upper case
         
     | 
| 
       178 
     | 
    
         
            -
                  env_key = key.upcase
         
     | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
       180 
     | 
    
         
            -
                  # Next, replace non-alphanumeric characters to underscore. This also
         
     | 
| 
       181 
     | 
    
         
            -
                  # collapses them into a single undescore.
         
     | 
| 
       182 
     | 
    
         
            -
                  env_key.gsub!(/[^[:alnum:]]+/, '_')
         
     | 
| 
       183 
     | 
    
         
            -
             
     | 
| 
       184 
     | 
    
         
            -
                  # Strip leading and trailing underscores.
         
     | 
| 
       185 
     | 
    
         
            -
                  env_key.gsub!(/^_*(.*?)_*$/, '\1')
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
                  return env_key
         
     | 
| 
       188 
     | 
    
         
            -
                end
         
     | 
| 
       189 
202 
     | 
    
         
             
              end # module EnvironmentOverride
         
     | 
| 
       190 
203 
     | 
    
         
             
            end # module Collapsium
         
     | 
| 
         @@ -9,6 +9,7 @@ 
     | 
|
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
            require 'collapsium/support/hash_methods'
         
     | 
| 
       11 
11 
     | 
    
         
             
            require 'collapsium/support/methods'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'collapsium/support/path_components'
         
     | 
| 
       12 
13 
     | 
    
         | 
| 
       13 
14 
     | 
    
         
             
            require 'collapsium/viral_capabilities'
         
     | 
| 
       14 
15 
     | 
    
         | 
| 
         @@ -27,40 +28,24 @@ module Collapsium 
     | 
|
| 
       27 
28 
     | 
    
         
             
              # for a path.
         
     | 
| 
       28 
29 
     | 
    
         
             
              module PathedAccess
         
     | 
| 
       29 
30 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
                 
     | 
| 
       31 
     | 
    
         
            -
                def separator
         
     | 
| 
       32 
     | 
    
         
            -
                  @separator ||= DEFAULT_SEPARATOR
         
     | 
| 
       33 
     | 
    
         
            -
                  return @separator
         
     | 
| 
       34 
     | 
    
         
            -
                end
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                ##
         
     | 
| 
       37 
     | 
    
         
            -
                # Assume any pathed access has this prefix.
         
     | 
| 
       38 
     | 
    
         
            -
                def path_prefix=(value)
         
     | 
| 
       39 
     | 
    
         
            -
                  @path_prefix = normalize_path(value)
         
     | 
| 
       40 
     | 
    
         
            -
                end
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                def path_prefix
         
     | 
| 
       43 
     | 
    
         
            -
                  @path_prefix ||= ''
         
     | 
| 
       44 
     | 
    
         
            -
                  return @path_prefix
         
     | 
| 
       45 
     | 
    
         
            -
                end
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
                # @api private
         
     | 
| 
       48 
     | 
    
         
            -
                # Default path separator
         
     | 
| 
       49 
     | 
    
         
            -
                DEFAULT_SEPARATOR = '.'.freeze
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
                ##
         
     | 
| 
       52 
     | 
    
         
            -
                # @return [RegExp] the pattern to split paths at; based on `separator`
         
     | 
| 
       53 
     | 
    
         
            -
                def split_pattern
         
     | 
| 
       54 
     | 
    
         
            -
                  /(?<!\\)#{Regexp.escape(separator)}/
         
     | 
| 
       55 
     | 
    
         
            -
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
                include ::Collapsium::Support::PathComponents
         
     | 
| 
       56 
32 
     | 
    
         | 
| 
       57 
33 
     | 
    
         
             
                ##
         
     | 
| 
       58 
34 
     | 
    
         
             
                # If the module is included, extended or prepended in a class, it'll
         
     | 
| 
       59 
35 
     | 
    
         
             
                # wrap accessor methods.
         
     | 
| 
       60 
36 
     | 
    
         
             
                class << self
         
     | 
| 
       61 
     | 
    
         
            -
                  include ::Collapsium::Support::HashMethods
         
     | 
| 
       62 
37 
     | 
    
         
             
                  include ::Collapsium::Support::Methods
         
     | 
| 
       63 
38 
     | 
    
         | 
| 
      
 39 
     | 
    
         
            +
                  # We want to wrap methods for Arrays and Hashes alike
         
     | 
| 
      
 40 
     | 
    
         
            +
                  READ_METHODS = (
         
     | 
| 
      
 41 
     | 
    
         
            +
                    ::Collapsium::Support::HashMethods::KEYED_READ_METHODS \
         
     | 
| 
      
 42 
     | 
    
         
            +
                    + ::Collapsium::Support::ArrayMethods::INDEXED_READ_METHODS
         
     | 
| 
      
 43 
     | 
    
         
            +
                  ).uniq.freeze
         
     | 
| 
      
 44 
     | 
    
         
            +
                  WRITE_METHODS = (
         
     | 
| 
      
 45 
     | 
    
         
            +
                    ::Collapsium::Support::HashMethods::KEYED_WRITE_METHODS \
         
     | 
| 
      
 46 
     | 
    
         
            +
                    + ::Collapsium::Support::ArrayMethods::INDEXED_WRITE_METHODS
         
     | 
| 
      
 47 
     | 
    
         
            +
                  ).uniq.freeze
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
       64 
49 
     | 
    
         
             
                  ##
         
     | 
| 
       65 
50 
     | 
    
         
             
                  # Returns a proc for either read or write access. Procs for write
         
     | 
| 
       66 
51 
     | 
    
         
             
                  # access will create intermediary hashes when e.g. setting a value for
         
     | 
| 
         @@ -90,18 +75,10 @@ module Collapsium 
     | 
|
| 
       90 
75 
     | 
    
         
             
                      # Try to find the leaf, based on the given components.
         
     | 
| 
       91 
76 
     | 
    
         
             
                      leaf = recursive_fetch(components, receiver, [], create: write_access)
         
     | 
| 
       92 
77 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
                      #  
     | 
| 
       94 
     | 
    
         
            -
                       
     | 
| 
       95 
     | 
    
         
            -
                       
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
                        #    itself was requested, and we really just need to delegate to its
         
     | 
| 
       98 
     | 
    
         
            -
                        #    wrapped_method.
         
     | 
| 
       99 
     | 
    
         
            -
                        meth = wrapped_method
         
     | 
| 
       100 
     | 
    
         
            -
                      else
         
     | 
| 
       101 
     | 
    
         
            -
                        # b) if the leaf is different from the receiver, we want to delegate
         
     | 
| 
       102 
     | 
    
         
            -
                        #    to the leaf.
         
     | 
| 
       103 
     | 
    
         
            -
                        meth = leaf.method(wrapped_method.name)
         
     | 
| 
       104 
     | 
    
         
            -
                      end
         
     | 
| 
      
 78 
     | 
    
         
            +
                      # Since Methods already contains loop prevention and we may want to
         
     | 
| 
      
 79 
     | 
    
         
            +
                      # call wrapped methods, let's just find the method to call from the
         
     | 
| 
      
 80 
     | 
    
         
            +
                      # leaf by name.
         
     | 
| 
      
 81 
     | 
    
         
            +
                      meth = leaf.method(wrapped_method.name)
         
     | 
| 
       105 
82 
     | 
    
         | 
| 
       106 
83 
     | 
    
         
             
                      # If the first argument was a symbol key, we want to use it verbatim.
         
     | 
| 
       107 
84 
     | 
    
         
             
                      # Otherwise we had pathed access, and only want to pass the last
         
     | 
| 
         @@ -112,8 +89,21 @@ module Collapsium 
     | 
|
| 
       112 
89 
     | 
    
         
             
                        the_args[0] = components.last
         
     | 
| 
       113 
90 
     | 
    
         
             
                      end
         
     | 
| 
       114 
91 
     | 
    
         | 
| 
      
 92 
     | 
    
         
            +
                      # Array methods we're modifying here are indexed, so the first argument
         
     | 
| 
      
 93 
     | 
    
         
            +
                      # must be an integer. Let's make it so :)
         
     | 
| 
      
 94 
     | 
    
         
            +
                      if leaf.is_a? Array
         
     | 
| 
      
 95 
     | 
    
         
            +
                        the_args[0] = the_args[0].to_i
         
     | 
| 
      
 96 
     | 
    
         
            +
                      end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
       115 
98 
     | 
    
         
             
                      # Then we can continue with that method.
         
     | 
| 
       116 
     | 
    
         
            -
                       
     | 
| 
      
 99 
     | 
    
         
            +
                      result = meth.call(*the_args, &block)
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                      # Sadly, we can't just return the result and be done with it.
         
     | 
| 
      
 102 
     | 
    
         
            +
                      # We need to tell the virality function (below) what we know about the
         
     | 
| 
      
 103 
     | 
    
         
            +
                      # result's path prefix, so we enhance the result value explicitly here.
         
     | 
| 
      
 104 
     | 
    
         
            +
                      result_path = receiver.path_components(receiver.path_prefix)
         
     | 
| 
      
 105 
     | 
    
         
            +
                      result_path += components
         
     | 
| 
      
 106 
     | 
    
         
            +
                      next ViralCapabilities.enhance_value(leaf, result, result_path)
         
     | 
| 
       117 
107 
     | 
    
         
             
                    end # proc
         
     | 
| 
       118 
108 
     | 
    
         
             
                  end # create_proc
         
     | 
| 
       119 
109 
     | 
    
         | 
| 
         @@ -138,11 +128,11 @@ module Collapsium 
     | 
|
| 
       138 
128 
     | 
    
         
             
                    base.extend(ViralCapabilities)
         
     | 
| 
       139 
129 
     | 
    
         | 
| 
       140 
130 
     | 
    
         
             
                    # Wrap all accessor functions to deal with paths
         
     | 
| 
       141 
     | 
    
         
            -
                     
     | 
| 
       142 
     | 
    
         
            -
                      wrap_method(base, method, &PATHED_ACCESS_READER)
         
     | 
| 
      
 131 
     | 
    
         
            +
                    READ_METHODS.each do |method|
         
     | 
| 
      
 132 
     | 
    
         
            +
                      wrap_method(base, method, raise_on_missing: false, &PATHED_ACCESS_READER)
         
     | 
| 
       143 
133 
     | 
    
         
             
                    end
         
     | 
| 
       144 
     | 
    
         
            -
                     
     | 
| 
       145 
     | 
    
         
            -
                      wrap_method(base, method, &PATHED_ACCESS_WRITER)
         
     | 
| 
      
 134 
     | 
    
         
            +
                    WRITE_METHODS.each do |method|
         
     | 
| 
      
 135 
     | 
    
         
            +
                      wrap_method(base, method, raise_on_missing: false, &PATHED_ACCESS_WRITER)
         
     | 
| 
       146 
136 
     | 
    
         
             
                    end
         
     | 
| 
       147 
137 
     | 
    
         
             
                  end
         
     | 
| 
       148 
138 
     | 
    
         | 
| 
         @@ -155,14 +145,6 @@ module Collapsium 
     | 
|
| 
       155 
145 
     | 
    
         
             
                    current_path << head
         
     | 
| 
       156 
146 
     | 
    
         
             
                    tail = path.slice(1, path.length)
         
     | 
| 
       157 
147 
     | 
    
         | 
| 
       158 
     | 
    
         
            -
                    # We know that the data has the current path. We also know that thanks to
         
     | 
| 
       159 
     | 
    
         
            -
                    # virality, data will respond to :path_prefix. So we might as well set the
         
     | 
| 
       160 
     | 
    
         
            -
                    # path, as long as it is more specific than what was previously there.
         
     | 
| 
       161 
     | 
    
         
            -
                    current_normalized = data.normalize_path(current_path)
         
     | 
| 
       162 
     | 
    
         
            -
                    if current_normalized.length > data.path_prefix.length
         
     | 
| 
       163 
     | 
    
         
            -
                      data.path_prefix = current_normalized
         
     | 
| 
       164 
     | 
    
         
            -
                    end
         
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
148 
     | 
    
         
             
                    # For the leaf element, we do nothing because that's where we want to
         
     | 
| 
       167 
149 
     | 
    
         
             
                    # dispatch to.
         
     | 
| 
       168 
150 
     | 
    
         
             
                    if path.length == 1
         
     | 
| 
         @@ -189,46 +171,29 @@ module Collapsium 
     | 
|
| 
       189 
171 
     | 
    
         
             
                end # class << self
         
     | 
| 
       190 
172 
     | 
    
         | 
| 
       191 
173 
     | 
    
         
             
                ##
         
     | 
| 
       192 
     | 
    
         
            -
                #  
     | 
| 
       193 
     | 
    
         
            -
                 
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
                   
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
             
     | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
       204 
     | 
    
         
            -
             
     | 
| 
       205 
     | 
    
         
            -
             
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
       207 
     | 
    
         
            -
             
     | 
| 
       208 
     | 
    
         
            -
                  return components.join(separator)
         
     | 
| 
       209 
     | 
    
         
            -
                end
         
     | 
| 
      
 174 
     | 
    
         
            +
                # Ensure that all values have their path_prefix set.
         
     | 
| 
      
 175 
     | 
    
         
            +
                def virality(value, *args)
         
     | 
| 
      
 176 
     | 
    
         
            +
                  # Figure out what path prefix to set on the value, if any.
         
     | 
| 
      
 177 
     | 
    
         
            +
                  # Candidates for the prefix are:
         
     | 
| 
      
 178 
     | 
    
         
            +
                  explicit = args[0] || []
         
     | 
| 
      
 179 
     | 
    
         
            +
                  from_self = path_components(path_prefix)
         
     | 
| 
      
 180 
     | 
    
         
            +
                  from_value = path_components(value.path_prefix)
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                  prefix = []
         
     | 
| 
      
 183 
     | 
    
         
            +
                  if not explicit.empty?
         
     | 
| 
      
 184 
     | 
    
         
            +
                    # If we got explicit information, we most likely want to use that.
         
     | 
| 
      
 185 
     | 
    
         
            +
                    prefix = explicit
         
     | 
| 
      
 186 
     | 
    
         
            +
                  elsif not from_self.empty?
         
     | 
| 
      
 187 
     | 
    
         
            +
                    # If we got information from self, that's the next best candidate.
         
     | 
| 
      
 188 
     | 
    
         
            +
                    prefix = from_self
         
     | 
| 
      
 189 
     | 
    
         
            +
                  end
         
     | 
| 
       210 
190 
     | 
    
         | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
       212 
     | 
    
         
            -
             
     | 
| 
       213 
     | 
    
         
            -
             
     | 
| 
       214 
     | 
    
         
            -
             
     | 
| 
       215 
     | 
    
         
            -
                  components = []
         
     | 
| 
       216 
     | 
    
         
            -
                  if path.respond_to?(:split) # likely a String
         
     | 
| 
       217 
     | 
    
         
            -
                    components = path_components(path)
         
     | 
| 
       218 
     | 
    
         
            -
                  elsif path.respond_to?(:join) # likely an Array
         
     | 
| 
       219 
     | 
    
         
            -
                    components = filter_components(path)
         
     | 
| 
      
 191 
     | 
    
         
            +
                  # However, if the value already has a better path prefix than either
         
     | 
| 
      
 192 
     | 
    
         
            +
                  # of the above, we want to keep that.
         
     | 
| 
      
 193 
     | 
    
         
            +
                  if prefix.length > from_value.length
         
     | 
| 
      
 194 
     | 
    
         
            +
                    value.path_prefix = normalize_path(prefix)
         
     | 
| 
       220 
195 
     | 
    
         
             
                  end
         
     | 
| 
       221 
     | 
    
         
            -
                  return separator + join_path(components)
         
     | 
| 
       222 
     | 
    
         
            -
                end
         
     | 
| 
       223 
196 
     | 
    
         | 
| 
       224 
     | 
    
         
            -
                ##
         
     | 
| 
       225 
     | 
    
         
            -
                # Ensure that all values have their path_prefix set.
         
     | 
| 
       226 
     | 
    
         
            -
                def virality(value)
         
     | 
| 
       227 
     | 
    
         
            -
                  # If a value was set via a nested Hash, it may not have got its
         
     | 
| 
       228 
     | 
    
         
            -
                  # path_prefix set during storing (i.e. x[key] = { nested: some_hash }
         
     | 
| 
       229 
     | 
    
         
            -
                  # In that case, we do always know that the value's path prefix is the same
         
     | 
| 
       230 
     | 
    
         
            -
                  # as the receiver.
         
     | 
| 
       231 
     | 
    
         
            -
                  value.path_prefix = path_prefix
         
     | 
| 
       232 
197 
     | 
    
         
             
                  return value
         
     | 
| 
       233 
198 
     | 
    
         
             
                end
         
     | 
| 
       234 
199 
     | 
    
         | 
| 
         @@ -0,0 +1,48 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # coding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # collapsium
         
     | 
| 
      
 4 
     | 
    
         
            +
            # https://github.com/jfinkhaeuser/collapsium
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
         
     | 
| 
      
 7 
     | 
    
         
            +
            # All rights reserved.
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            module Collapsium
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              ##
         
     | 
| 
      
 13 
     | 
    
         
            +
              # Support functionality for Collapsium
         
     | 
| 
      
 14 
     | 
    
         
            +
              module Support
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                ##
         
     | 
| 
      
 17 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 18 
     | 
    
         
            +
                # Defines which read and write functions we expect Array to have.
         
     | 
| 
      
 19 
     | 
    
         
            +
                module ArrayMethods
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # Read access methods with index parameter
         
     | 
| 
      
 23 
     | 
    
         
            +
                  INDEXED_READ_METHODS = [
         
     | 
| 
      
 24 
     | 
    
         
            +
                    :[], :at, :fetch, :include?,
         
     | 
| 
      
 25 
     | 
    
         
            +
                  ].freeze
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # All read access methods
         
     | 
| 
      
 29 
     | 
    
         
            +
                  READ_METHODS = INDEXED_READ_METHODS + [
         
     | 
| 
      
 30 
     | 
    
         
            +
                    :dup, :first, :last, :take, :drop,
         
     | 
| 
      
 31 
     | 
    
         
            +
                  ].freeze
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # Write access methods with index parameter
         
     | 
| 
      
 35 
     | 
    
         
            +
                  INDEXED_WRITE_METHODS = [
         
     | 
| 
      
 36 
     | 
    
         
            +
                    :[]=, :insert, :compact,
         
     | 
| 
      
 37 
     | 
    
         
            +
                  ].freeze
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  # All write access methods
         
     | 
| 
      
 40 
     | 
    
         
            +
                  WRITE_METHODS = INDEXED_WRITE_METHODS + [
         
     | 
| 
      
 41 
     | 
    
         
            +
                    :unshift, :pop, :shift,
         
     | 
| 
      
 42 
     | 
    
         
            +
                  ].freeze
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                end # module ArrayMethods
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              end # module Support
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            end # module Collapsium
         
     |