call_by_need 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg/*
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- call_by_need (0.1.0)
4
+ call_by_need (0.1.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2013 fronx
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
13
+ all 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
21
+ THE SOFTWARE.
@@ -25,7 +25,7 @@ module CallByNeed
25
25
  end
26
26
 
27
27
  def get(name)
28
- if var_get(name).respond_to?(:call)
28
+ unless evaluated?(name)
29
29
  store[name] = var_get(name).call(self)
30
30
  else
31
31
  var_get(name)
@@ -40,6 +40,10 @@ module CallByNeed
40
40
  var_get(key)
41
41
  end
42
42
 
43
+ def evaluated?(name)
44
+ !var_get(name).respond_to?(:call)
45
+ end
46
+
43
47
  private
44
48
  def var_get(name)
45
49
  if store.has_key?(name)
@@ -1,3 +1,3 @@
1
1
  module CallByNeed
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/readme.md CHANGED
@@ -1,3 +1,112 @@
1
1
  # Call By Need
2
2
 
3
3
  So yeah, uhm, you can read about what that means on [Wikipedia](http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_need). It's like an on-line encyclopedia type thing.
4
+
5
+ ## Examples
6
+
7
+ ### Simple memoization
8
+
9
+ ```ruby
10
+ require 'call_by_need'
11
+
12
+ c = CallByNeed::Context.new do |c|
13
+ c.declare(:b) { |x| x.a + 10 }
14
+ c.declare(:a) { Time.now.utc }
15
+ end
16
+
17
+ c.a
18
+ # => 2013-09-07 14:48:55 UTC
19
+ c.b
20
+ # => 2013-09-07 14:49:05 UTC
21
+ c.a
22
+ # => 2013-09-07 14:48:55 UTC
23
+ ```
24
+
25
+ ### Merging of contexts
26
+
27
+ ```ruby
28
+ require 'call_by_need'
29
+
30
+ c1 = CallByNeed::Context.new do |c|
31
+ c.declare(:a, &:b) # b doesn't exist yet
32
+ c.declare(:x) { |x| x.b + 'x' }
33
+ end
34
+
35
+ c1.a
36
+ # NoMethodError: undefined method `b'
37
+
38
+ c2 = CallByNeed::Context.new(c1) do |c|
39
+ c.declare(:b) { 'b' }
40
+ end
41
+
42
+ c2.a
43
+ # => 'b'
44
+ c2.x
45
+ # => 'bx'
46
+ ```
47
+
48
+ ### You can also give your contexts names
49
+
50
+ This example is ultimately pointless, but it shows some more elaborate potential usage context that involves slow things and fast things.
51
+
52
+ ```ruby
53
+ require 'call_by_need'
54
+ require 'benchmark'
55
+
56
+ class Genderizer
57
+ def self.genders(name)
58
+ [].tap do |_genders|
59
+ _genders << :girl if girl?(name)
60
+ _genders << :boy if boy?(name)
61
+ end
62
+ end
63
+
64
+ def self.girl?(name)
65
+ sleep(0.5)
66
+ name =~ /^[amk]/
67
+ end
68
+
69
+ def self.boy?(name)
70
+ sleep(0.5)
71
+ name =~ /^[bk]/
72
+ end
73
+ end
74
+
75
+ class People
76
+ include CallByNeed
77
+
78
+ def initialize(genderizer)
79
+ declare(:kids) do
80
+ [ 'alice', 'bob', 'marie', 'kim' ]
81
+ end
82
+ declare(:genders) do |x|
83
+ x.kids.inject({}) do |acc, name|
84
+ acc.merge!(name => genderizer.genders(name))
85
+ end
86
+ end
87
+ declare(:girls) do |x|
88
+ x.kids.select { |name| genders[name].include?(:girl) }
89
+ end
90
+ declare(:boys) do |x|
91
+ x.kids.select { |name| genders[name].include?(:boy) }
92
+ end
93
+ declare(:unknown) do |x|
94
+ x.kids.select { |name| [ :boy, :girl ] & genders[name] == [ :boy, :girl ] }
95
+ end
96
+ end
97
+ end
98
+
99
+ people = People.new(Genderizer)
100
+ people.evaluated?(:unknown)
101
+ # => false
102
+ Benchmark.realtime { people.girls }
103
+ # => 4.005
104
+ people.evaluated?(:unknown)
105
+ # => false
106
+ Benchmark.realtime { people.unknown }
107
+ # => 0.00003
108
+ ```
109
+
110
+ ## Okay…
111
+
112
+ It's basically just a generalized `||=`. So maybe the name is a little misleading.
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: call_by_need
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.0
5
+ version: 0.1.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - fronx
@@ -44,8 +44,10 @@ extensions: []
44
44
  extra_rdoc_files: []
45
45
 
46
46
  files:
47
+ - .gitignore
47
48
  - Gemfile
48
49
  - Gemfile.lock
50
+ - LICENSE
49
51
  - Rakefile
50
52
  - call_by_need.gemspec
51
53
  - lib/call_by_need.rb
@@ -67,7 +69,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
69
  requirements:
68
70
  - - ">="
69
71
  - !ruby/object:Gem::Version
70
- hash: 1747255289361994175
72
+ hash: -360440508039470097
71
73
  segments:
72
74
  - 0
73
75
  version: "0"
@@ -76,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
78
  requirements:
77
79
  - - ">="
78
80
  - !ruby/object:Gem::Version
79
- hash: 1747255289361994175
81
+ hash: -360440508039470097
80
82
  segments:
81
83
  - 0
82
84
  version: "0"