lab42_ihash 0.0.1.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 340ee6217f0f1fabdcc7d5af631fe6c40982b6e9
4
+ data.tar.gz: ec83fb030f1ae017e193525fcedae4c8e335606b
5
+ SHA512:
6
+ metadata.gz: 90f46bf55fb52af4d0d6deda21421d66e2f530c2f27869a8f2348eb48160387f35ce15fb1af1f83e9e529af76258013836367eb98aebf23ac9d711c150fee9fd
7
+ data.tar.gz: 1f67e0a1699424b0e0e45a21fe740cadb0e0db02e5cc94420c7ca7562cc0ad10ec90417468fe82c678120f66888286a54d441e92805ac021bf5769b09a7b8176
data/.gitignore ADDED
@@ -0,0 +1,35 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
35
+ .tmux
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format documentation
3
+ --tag ~js
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ lab42_intellihash (0.0.1)
5
+ forwarder2 (~> 0.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ae (1.8.2)
11
+ ansi
12
+ ansi (1.4.3)
13
+ brass (1.2.1)
14
+ coderay (1.1.0)
15
+ diff-lcs (1.2.5)
16
+ facets (2.9.3)
17
+ forwarder2 (0.2.0)
18
+ method_source (0.8.2)
19
+ pry (0.9.12.6)
20
+ coderay (~> 1.0)
21
+ method_source (~> 0.8)
22
+ slop (~> 3.4)
23
+ pry-nav (0.2.3)
24
+ pry (~> 0.9.10)
25
+ qed (2.9.1)
26
+ ansi
27
+ brass
28
+ facets (>= 2.8)
29
+ rspec (2.14.1)
30
+ rspec-core (~> 2.14.0)
31
+ rspec-expectations (~> 2.14.0)
32
+ rspec-mocks (~> 2.14.0)
33
+ rspec-core (2.14.8)
34
+ rspec-expectations (2.14.5)
35
+ diff-lcs (>= 1.1.3, < 2.0)
36
+ rspec-mocks (2.14.6)
37
+ slop (3.5.0)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ ae (~> 1.8)
44
+ bundler (~> 1.6)
45
+ lab42_intellihash!
46
+ pry (~> 0.9)
47
+ pry-nav (~> 0.2)
48
+ qed (~> 2.9)
49
+ rspec (~> 2.14)
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Robert Dober
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # lab42_ihash
2
+
3
+ A Hash with Business Logic ( call it intelligent ).
4
+
5
+ Actually it is a view layer over a Hash like object, which needs to obey the simple protocol
6
+
7
+ `Hash#fetch`.
8
+
9
+
10
+ The services `IHash` provides are of the number of four:
11
+
12
+ * Default values per key.
13
+ * Validation via _Constraints_.
14
+ * Business Logic or Lookup Logic.
15
+ * Caching of Computed Values.
16
+
17
+
18
+ ## Installation
19
+
20
+ ```sh
21
+ gem install lab42_ihash --pre
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```ruby
27
+ require 'lab42/ihash'
28
+
29
+ IHash = Lab42::IHash
30
+ ```
31
+
32
+
33
+ ## Manual (QED Driven)
34
+
35
+ Details are explained in the [QED](https://github.com/rubyworks/qed) demos [here](https://github.com/RobertDober/lab42_intellihash/tree/master/demo)
@@ -0,0 +1,109 @@
1
+ # IHash QED
2
+
3
+ ## Introduction
4
+
5
+ An `IHash` is an object that lets us define an _intelligent_ way to access a Hash like object.
6
+
7
+
8
+ The services `IHash` provides are of the number of four:
9
+
10
+ * Default values per key.
11
+ * Validation via _Constraints_.
12
+ * Business Logic or Lookup Logic.
13
+ * Caching of Computed Values.
14
+
15
+ ## Defaults
16
+
17
+
18
+ ### Predefined
19
+
20
+ The simplest meaningful example could look like the following:
21
+
22
+ ```ruby
23
+ ihash = IHash.new a: 1, b: 2
24
+
25
+ ihash.get( :a ).assert == 1
26
+ ihash.get( :b ).assert == 2
27
+ ihash.set_values a: 42
28
+ ihash.get( :a ).assert == 42
29
+ # Defaults are not changed:
30
+ ihash.get( :b ).assert == 2
31
+ ```
32
+
33
+ Alternatively the `set_defaults` method can be used:
34
+
35
+ ```ruby
36
+ ihash.set_defaults a: 1, c: 2
37
+ # values are not touched
38
+ ihash.get( :a ).assert == 42
39
+ # new default values are in place
40
+ ihash.get( :c ).assert == 2
41
+ # But the old defaults have been lost
42
+ KeyError.assert.raised? do
43
+ ihash.get :b
44
+ end
45
+ ```
46
+
47
+ ### Defaults provided via a parameter
48
+
49
+ ```ruby
50
+ ihash = IHash.new a: 1
51
+
52
+ ihash.get( :a ).assert == 1
53
+ ihash.get( :a, 42 ).assert == 42
54
+
55
+ # However values override the default of course
56
+ ihash.set_values a: 2
57
+ ihash.get( :a, 42 ).assert == 2
58
+
59
+ ```
60
+
61
+
62
+ ### Computed Defaults
63
+
64
+ They are the main reason for caching, but as defaults provided
65
+ via parameters override cached values, we will need an alternative
66
+ calculation mechanisme for business logic, which we will discuss
67
+ later on.
68
+
69
+ For know all we need to know to understand the following example
70
+ is that `Proc` instances as default values will be evaluated
71
+ in the `IHash` instance's context.
72
+
73
+ ```ruby
74
+ rectangle = IHash.new \
75
+ height: ->{ get( :surface ) / get( :width ) },
76
+ width: ->{ get( :surface ) / get( :height ) },
77
+ surface: ->{ get( :width ) * get( :height ) }
78
+
79
+ # Obviously we need some data here. The following code
80
+ # will consume the whole stack before crashing.
81
+ # Later on we will see how to avoid this by means
82
+ # of defaults and constraints, and hopefully a later version
83
+ # of IHash will detect the mutual infinite recursion.
84
+
85
+ # rectangle.get :surface
86
+
87
+ # So let us provide some data
88
+ rectangle.set_values width: 20, height: 30
89
+ rectangle.get( :surface ).assert == 600
90
+ ```
91
+
92
+ Now it would be nice if we could avoid the potential stack overflow
93
+ by means of defaults.
94
+ And, as promised, we can:
95
+
96
+ ```ruby
97
+
98
+ rectangle = IHash.new \
99
+ height: ->{ get( :surface, 600 ) / get( :width, 20 ) },
100
+ width: ->{ get( :surface, 600 ) / get( :height ) },
101
+ surface: ->{ get( :width ) * get( :height ) }
102
+
103
+ # These defaults shall be sufficent
104
+ rectangle.get( :surface ).assert == 600
105
+ # and they are.
106
+
107
+ ```
108
+
109
+ To see how to do this with constraints, please refer to the [constraints demo](https://github.com/RobertDober/lab42_intellihash/blob/master/demo/050-constraints.md)
@@ -0,0 +1,70 @@
1
+ # IHash QED
2
+
3
+ ## Constraints
4
+
5
+ Constraints are evaluated whenever the values of an `IHash` instance are set via the `set_values` method.
6
+
7
+ The result of this evaluation is stored for later validation.
8
+
9
+ Let us dive into a simple example:
10
+
11
+ ```ruby
12
+ ihash = IHash.new
13
+ .set_constraints(
14
+ a: ->(eventual_value_for_a){ eventual_value_for_a == 42 } )
15
+ .set_values a: 43
16
+
17
+ ihash.valid?.assert == false
18
+ ihash.errors.empty?.assert == false
19
+ ihash.errors.first.assert =~ /value error for key :a and value 43/
20
+
21
+ ihash.set_values a: 42
22
+ ihash.valid?.assert == true
23
+ ihash.errors.empty?.assert == true
24
+
25
+ ```
26
+
27
+ In order to implement an early failure policy you need to raise exceptions yourself.
28
+
29
+ ```ruby
30
+ ArgumentError.assert.raised? do
31
+ ihash =
32
+ IHash.new
33
+ .set_constraints\
34
+ a: ->(value){ value == 42 or raise ArgumentError }
35
+
36
+ ihash.set_values a: 41
37
+ end
38
+ ```
39
+
40
+ Maybe a `set_constraints!` method doing something like that for you can be
41
+ implemented later on.
42
+
43
+ Oh and I am so glad you asked, before setting values, constraints are not enforced and
44
+ the instance is therefore valid in all cases:
45
+
46
+ ```ruby
47
+ ihash = IHash.new( a: nil ).set_constraints a: ->{ raise ArgumentError }
48
+
49
+ ihash.valid?.assert == true
50
+
51
+ ArgumentError.assert.raised? do
52
+ ihash.set_values b: nil
53
+ end
54
+ ihash.valid?.assert == false
55
+ ihash.errors.first.assert == 'constraint for key :a raised an error ArgumentError'
56
+ ```
57
+
58
+ And this works for calculated values too, of course:
59
+
60
+ ```ruby
61
+ ihash = IHash
62
+ .new( a: ->{ - get( :b ) } )
63
+ .set_constraints( a: ->(val){ val > 0 } )
64
+ .set_values b: 42
65
+
66
+ ihash.valid?.assert == false
67
+
68
+ ```
69
+
70
+
@@ -0,0 +1,12 @@
1
+ # IHash QED
2
+
3
+ ## Business Logic
4
+
5
+ _Not implemented_
6
+
7
+ For the time being the defaults semantics serve all YHS' needs. But he believes
8
+ that more complex computations, recursion detection, a seperate cache that
9
+ would override default parameters and other subtle differences might come forth
10
+ one day.
11
+
12
+
@@ -0,0 +1,77 @@
1
+ # IHash QED
2
+
3
+ ## Caching
4
+
5
+ Will only occur when lookup values or default values are accessed.
6
+
7
+ Actually `#cache` is exposed as an attribute, but manipulate it not (or at your
8
+ own risk).
9
+
10
+ ```ruby
11
+ ihash = IHash.new \
12
+ a: ->{ 42 },
13
+ b: 42
14
+
15
+ # The cache is empty
16
+ ihash.cache.assert.empty?
17
+
18
+ # Let us access :b
19
+ ihash.get :b
20
+ # The cache is not empty any more
21
+ ihash.cache.refute.empty?
22
+ # It has been filled with :b only
23
+ ihash.cache.assert.has_key? :b
24
+ ihash.cache.refute.has_key? :a
25
+ # And now we add :a
26
+ ihash.get :a
27
+ ihash.cache.assert.has_key? :b
28
+ ihash.cache.assert.has_key? :a
29
+
30
+ ```
31
+
32
+ ### Setting values invalidates the cache
33
+
34
+ ```ruby
35
+ ihash.set_values b: 56
36
+
37
+ # Cache is empty again
38
+ ihash.cache.assert.empty?
39
+ # Values come before the cache, but don't do that
40
+ ihash.cache[ :b ] = 22
41
+ ihash.get( :b ).assert == 56
42
+ # We did not even break anything
43
+ ihash.get( :a ).assert == 42
44
+ ihash.cache.assert.has_key? :a
45
+
46
+ ```
47
+
48
+ ### Value access does not populate the cache
49
+
50
+ ```ruby
51
+ ihash.set_values b: 29
52
+
53
+ ihash.cache.assert.empty?
54
+ ihash.get( :b ).assert == 29
55
+ ihash.cache.assert.empty?
56
+ ```
57
+
58
+
59
+ ### Setting defaults invalidates the cache too
60
+
61
+ ```ruby
62
+ ihash.get :a
63
+ ihash.cache.keys.assert == [:a]
64
+ ihash.set_defaults
65
+ # The following is not very wise, maybe setting values, defaults
66
+ # or constraints will reset the instance.
67
+ # Not sure: ihash.get( :b ).assert == 29
68
+ ihash.cache.assert.empty?
69
+
70
+ ```
71
+
72
+
73
+ This behavior might change with minor version updates as it is not very
74
+ intuitive.
75
+
76
+ Now that we are aware how caching and default values work let us go further with constraints
77
+
@@ -0,0 +1 @@
1
+ require 'ae'
@@ -0,0 +1,4 @@
1
+ LIBRARY_PATH = File.expand_path '../../lib'
2
+
3
+ require 'lab42/ihash'
4
+ IHash = Lab42::IHash
@@ -0,0 +1,37 @@
1
+
2
+ base = File.dirname __FILE__
3
+ $:.unshift File.join( base, 'lib' )
4
+
5
+ require 'lab42/ihash/version'
6
+
7
+ Gem::Specification.new do | spec |
8
+ spec.name = 'lab42_ihash'
9
+ spec.version = Lab42::IHash::VERSION
10
+ spec.authors = ['Robert Dober']
11
+ spec.email = %w{ robert.dober@gmail.com }
12
+ spec.description = %{A Hash with Business Logic (call it intelligent).}
13
+ spec.summary = %{A view over Hash like objects (needs to implement #fetch only).
14
+ Allowing to specify defaults, constraints and business logic. Implements caching for computed values.}
15
+ spec.homepage = %{https://github.com/RobertDober/lab42_ihash}
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.test_files = spec.files.grep(%r{\Atest|\Aspec|\Afeatures|\Ademo/})
20
+ spec.require_paths = %w{lib}
21
+
22
+ # spec.post_install_message = %q{ }
23
+
24
+
25
+ spec.required_ruby_version = '>= 2.0.0'
26
+ spec.required_rubygems_version = '>= 2.2.2'
27
+
28
+ # spec.add_dependency 'forwarder2', '~> 0.2'
29
+
30
+ spec.add_development_dependency 'bundler', '~> 1.6'
31
+ spec.add_development_dependency 'rspec', '~> 2.14'
32
+ spec.add_development_dependency 'pry', '~> 0.9'
33
+ spec.add_development_dependency 'pry-nav', '~> 0.2'
34
+ spec.add_development_dependency 'ae', '~> 1.8'
35
+ spec.add_development_dependency 'qed', '~> 2.9'
36
+
37
+ end
@@ -0,0 +1,5 @@
1
+ module Lab42
2
+ class IHash
3
+ VERSION = '0.0.1.beta'
4
+ end # class IHash
5
+ end # module Lab42
@@ -0,0 +1,89 @@
1
+ module Lab42
2
+ class IHash
3
+ attr_reader :cache, :constraints, :defaults, :errors, :values
4
+
5
+ def get key, *default
6
+ values.fetch key do
7
+ lookup( key, *default )
8
+ end
9
+ end
10
+
11
+ def set_constraints(**constraints)
12
+ @constraints << constraints
13
+ self
14
+ end
15
+
16
+ def set_defaults(**defaults)
17
+ invalidate_cache_and_errors
18
+ @defaults = defaults
19
+ self
20
+ end
21
+
22
+ def set_values a_hashy={}
23
+ invalidate_cache_and_errors
24
+
25
+ @values = a_hashy.dup rescue a_hashy
26
+ validate_constraints
27
+ self
28
+ end
29
+
30
+ def valid?; errors.empty? end
31
+
32
+ private
33
+ def evaluate val_or_proc
34
+ return evaluate_proc val_or_proc if Proc===val_or_proc
35
+ val_or_proc
36
+ end
37
+
38
+ def evaluate_proc a_proc
39
+ a_proc.arity == 1 ? instance_eval( &a_proc ) : instance_exec( &a_proc )
40
+ end
41
+
42
+ def initialize(**defaults)
43
+ set_defaults(**defaults)
44
+
45
+ @cache = {}
46
+ @values = {}
47
+
48
+ @constraints = []
49
+ @errors = []
50
+ end
51
+
52
+ def invalidate_cache_and_errors
53
+ @cache = {}
54
+ @errors = []
55
+ end
56
+
57
+ # Precondition: key not in values and key not in cache
58
+ # This explains the default value provided priority, we reason:
59
+ # An explicit default value in a get shall override the predefined defaults
60
+ # **But** that means that later caching will change the behavior of get not
61
+ # my preferred programming style. This might change in the future. (E.g.
62
+ # default comes before cache lookup).
63
+ def lookup key, *default
64
+ return default.first unless default.empty?
65
+ cache.fetch key do
66
+ raise KeyError, "#{key} not found in values, defaults or logic" unless defaults.has_key? key
67
+ cache[ key ] = evaluate( defaults[key] )
68
+ end
69
+ end
70
+
71
+ def validate_constraints
72
+ constraints.each do | constraint |
73
+ constraint.each do | k, c |
74
+ v = get k
75
+ if c.arity == 1
76
+ c.(v) || errors << "value error for key #{k.inspect} and value #{v.inspect}"
77
+ else
78
+ begin
79
+ instance_exec(&c) || errors << "value error for key #{k.inspect} and value #{v.inspect}"
80
+ rescue StandardError => e
81
+ errors << "constraint for key #{k.inspect} raised an error #{e}"
82
+ raise
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end # class IHash
89
+ end # module Lab42
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lab42_ihash
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.beta
5
+ platform: ruby
6
+ authors:
7
+ - Robert Dober
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-nav
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ae
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: qed
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '2.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '2.9'
97
+ description: A Hash with Business Logic (call it intelligent).
98
+ email:
99
+ - robert.dober@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - .gitignore
105
+ - .rspec
106
+ - Gemfile
107
+ - Gemfile.lock
108
+ - LICENSE
109
+ - README.md
110
+ - demo/000-introduction.md
111
+ - demo/050-constraints.md
112
+ - demo/080-business-logic.md
113
+ - demo/100-caching.md
114
+ - demo/applique/require_ae.rb
115
+ - demo/applique/require_ihash.rb
116
+ - lab42_ihash.gemspec
117
+ - lib/lab42/ihash.rb
118
+ - lib/lab42/ihash/version.rb
119
+ homepage: https://github.com/RobertDober/lab42_ihash
120
+ licenses:
121
+ - MIT
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: 2.0.0
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - '>='
135
+ - !ruby/object:Gem::Version
136
+ version: 2.2.2
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.2.2
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: 'A view over Hash like objects (needs to implement #fetch only). Allowing
143
+ to specify defaults, constraints and business logic. Implements caching for computed
144
+ values.'
145
+ test_files:
146
+ - demo/000-introduction.md
147
+ - demo/050-constraints.md
148
+ - demo/080-business-logic.md
149
+ - demo/100-caching.md
150
+ - demo/applique/require_ae.rb
151
+ - demo/applique/require_ihash.rb