methodhash 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.
data/README ADDED
@@ -0,0 +1,121 @@
1
+ NAME
2
+
3
+ methodhash
4
+
5
+ SYNOPSIS
6
+
7
+ A Hash subclass for automatic storage of values obtained from a method
8
+ defined by the user. Useful for lengthy calculations on large datasets.
9
+
10
+ URI
11
+
12
+ http://rubyforge.org/projects/methodhash
13
+ http://github.com/fredrikj/methodhash
14
+
15
+ INSTALL
16
+
17
+ gem install methodhash
18
+
19
+ DESCRIPTION
20
+
21
+ A Hash subclass that defines its values from a specified method.
22
+ Use it by creating a subclass of MethodHash, and define a method
23
+ with the name "mymethod" in it. Like this (same code in samples/samples.rb):
24
+
25
+ # 1. Simple use
26
+ class AddOne < MethodHash
27
+ def mymethod(a)
28
+ sleep 3
29
+ a + 1
30
+ end
31
+ end
32
+
33
+ a = AddOne.new
34
+ a # {}
35
+ a[1] # 2
36
+ a[7] # 8
37
+ a # {1=>2, 7=>8}
38
+ puts a.dump # --- !map:AddOne
39
+ # 1: 2
40
+ # 7: 8
41
+
42
+
43
+ # 2. With a file
44
+ b = AddOne.new '/tmp/one.yml'
45
+ b # {}
46
+ b[1] # 2
47
+ b.dump # '/tmp/one.yml'
48
+ c = AddOne.new '/tmp/one.yml'
49
+ puts c.inspect # {1=>2}
50
+
51
+
52
+ # 3. Some protection against data corruption.
53
+ class AddTwo < MethodHash
54
+ def mymethod(a)
55
+ a + 2
56
+ end
57
+ end
58
+
59
+ begin
60
+ d = AddTwo.new '/tmp/one.yml' # ArgumentError: Path holds class AddOne
61
+ rescue
62
+ puts $!
63
+ end
64
+
65
+
66
+ # 4. Saving exceptions arising from mymethod.
67
+ class AddOneFaulty < MethodHash
68
+ def mymethod(a)
69
+ rand(2)==0 ? raise("Epic Fail!") : a+1
70
+ end
71
+ end
72
+
73
+ e = AddOneFaulty.new
74
+ e[1] # RuntimeError: Epic Fail! # If something bad happened
75
+ e # {1=>"ERROR: Epic Fail!"}
76
+ e.retry_errors # false
77
+ e[1] # RuntimeError: Epic Fail! # Still keeping the error
78
+ e.retry_errors=true # true
79
+ e[1] # 2 # If better luck this time
80
+ e # {1=>2}
81
+
82
+
83
+ # 5. A more complex setting
84
+ class AddThree < MethodHash
85
+ def initialize(path1=nil, path2=nil, mypath=nil)
86
+ @one = AddOne.new(path1)
87
+ @two = AddTwo.new(path2)
88
+ super(mypath)
89
+ end
90
+
91
+ def mymethod(a)
92
+ @one[a] + @two[a] - a
93
+ end
94
+
95
+ def dump
96
+ @one.dump
97
+ @two.dump
98
+ super
99
+ end
100
+ end
101
+
102
+ f = AddThree.new( '/tmp/one.yml', '/tmp/two.yml')
103
+ puts f[3]
104
+ f.dump
105
+
106
+
107
+ # 6. With two arguments
108
+ class Add < MethodHash
109
+ def mymethod(a,b)
110
+ a + b
111
+ end
112
+ end
113
+
114
+
115
+
116
+
117
+ HISTORY
118
+ 0.5.0
119
+
120
+ Initial version
121
+
data/lib/methodhash.rb ADDED
@@ -0,0 +1,93 @@
1
+ require 'yaml'
2
+
3
+ class MethodHash < Hash
4
+
5
+ attr_accessor :retry_errors, :force_calc
6
+ attr_reader :changed, :path
7
+ alias_method :originalassign, :[]=
8
+
9
+ # --- initialize ---
10
+ # A path is optional but necessary if you want to store the Hash to disk.
11
+ def initialize(path=nil)
12
+ unless self.respond_to? :mymethod
13
+ raise ArgumentError,
14
+ "No calculation method (with name 'mymethod') defined for #{self.class}"
15
+ end
16
+ if self.class.to_s == 'MethodHash'
17
+ raise ArgumentError, "Make a subclass. Don't use MethodHash directly."
18
+ end
19
+ @path = path
20
+ @changed = false
21
+ @retry_errors = false
22
+ @force_calc = false
23
+ if @path and File.exists? @path
24
+ hash = YAML.load open(@path)
25
+ raise ArgumentError, "Path holds class #{hash.class}" if hash.class != self.class
26
+ self.merge! hash
27
+ end
28
+ end
29
+
30
+ # --- [] ---
31
+ # If not previously called with given arguments, calls 'mymethod'
32
+ # with the arguments and inserts the answer in the Hash.
33
+ # If force_calc is set to true, mymethod is always called.
34
+ # If retry_errors is set to true, mymethod is also called if value
35
+ # has previously been retrieved but raised an error at that time.
36
+ def [](*arg)
37
+ arg = arg.first if arg.size==1
38
+ if !force_calc and s=super(arg)
39
+ if s.is_a? String and s[0,6]=='ERROR:'
40
+ if @retry_errors
41
+ self.delete arg
42
+ self.[](*arg)
43
+ else
44
+ raise s[7..-1]
45
+ end
46
+ else
47
+ s
48
+ end
49
+ else
50
+ @changed = true
51
+ begin
52
+ originalassign(arg,self.mymethod(*arg))
53
+ rescue
54
+ originalassign(arg,"ERROR: #{$!}")
55
+ raise
56
+ end
57
+ end
58
+ end
59
+
60
+ # --- []= ---
61
+ # This method cannot be used.
62
+ def []=(key, value)
63
+ raise "You can't just put values into a #{self.class}."
64
+ end
65
+
66
+ # --- dump ---
67
+ # If a path has been given, writes self to that file and returns the path.
68
+ # Otherwise, returns a string containing the dump.
69
+ def dump
70
+ if @path
71
+ if self.changed?
72
+ open(@path,'w'){|f| YAML.dump(self,f) }
73
+ @changed = false
74
+ end
75
+ @path
76
+ elsif !path
77
+ @changed = false
78
+ YAML.dump(self)
79
+ end
80
+ end
81
+
82
+ def delete(arg)
83
+ @changed = true
84
+ super
85
+ end
86
+
87
+ # --- changed? ---
88
+ # Has something changed since the last call to dump?
89
+ def changed?
90
+ @changed
91
+ end
92
+
93
+ end
@@ -0,0 +1,24 @@
1
+ ## methodhash.gemspec
2
+ #
3
+
4
+ Gem::Specification::new do |spec|
5
+ spec.name = "methodhash"
6
+ spec.description = 'A Hash for automatic storage of values obtained from a method defined by the user.'
7
+ spec.version = "0.5.0"
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.summary = 'methodhash'
10
+
11
+ spec.files = ["methodhash.gemspec", "lib", "lib/methodhash.rb", "README", "samples", "samples/samples.rb"]
12
+ spec.executables = []
13
+
14
+ spec.require_path = "lib"
15
+
16
+ spec.has_rdoc = true
17
+
18
+ spec.extensions.push(*[])
19
+
20
+ spec.rubyforge_project = "methodhash"
21
+ spec.author = "Fredrik Johansson"
22
+ spec.email = "fredjoha@gmail.com"
23
+ spec.homepage = "http://github.com/fredrikj/methodhash/tree/master"
24
+ end
@@ -0,0 +1,88 @@
1
+ # 1. Simple use
2
+ class AddOne < MethodHash
3
+ def mymethod(a)
4
+ sleep 3
5
+ a + 1
6
+ end
7
+ end
8
+
9
+ a = AddOne.new
10
+ a # {}
11
+ a[1] # 2
12
+ a[7] # 8
13
+ a # {1=>2, 7=>8}
14
+ puts a.dump # --- !map:AddOne
15
+ # 1: 2
16
+ # 7: 8
17
+
18
+
19
+ # 2. With a file
20
+ b = AddOne.new '/tmp/one.yml'
21
+ b # {}
22
+ b[1] # 2
23
+ b.dump # '/tmp/one.yml'
24
+ c = AddOne.new '/tmp/one.yml'
25
+ puts c.inspect # {1=>2}
26
+
27
+
28
+ # 3. Some protection against data corruption.
29
+ class AddTwo < MethodHash
30
+ def mymethod(a)
31
+ a + 2
32
+ end
33
+ end
34
+
35
+ begin
36
+ d = AddTwo.new '/tmp/one.yml' # ArgumentError: Path holds class AddOne
37
+ rescue
38
+ puts $!
39
+ end
40
+
41
+
42
+ # 4. Saving exceptions arising from mymethod.
43
+ class AddOneFaulty < MethodHash
44
+ def mymethod(a)
45
+ rand(2)==0 ? raise("Epic Fail!") : a+1
46
+ end
47
+ end
48
+
49
+ e = AddOneFaulty.new
50
+ e[1] # RuntimeError: Epic Fail! # If something bad happened
51
+ e # {1=>"ERROR: Epic Fail!"}
52
+ e.retry_errors # false
53
+ e[1] # RuntimeError: Epic Fail! # Still keeping the error
54
+ e.retry_errors=true # true
55
+ e[1] # 2 # If better luck this time
56
+ e # {1=>2}
57
+
58
+
59
+ # 5. A more complex setting
60
+ class AddThree < MethodHash
61
+ def initialize(path1=nil, path2=nil, mypath=nil)
62
+ @one = AddOne.new(path1)
63
+ @two = AddTwo.new(path2)
64
+ super(mypath)
65
+ end
66
+
67
+ def mymethod(a)
68
+ @one[a] + @two[a] - a
69
+ end
70
+
71
+ def dump
72
+ @one.dump
73
+ @two.dump
74
+ super
75
+ end
76
+ end
77
+
78
+ f = AddThree.new( '/tmp/one.yml', '/tmp/two.yml')
79
+ puts f[3]
80
+ f.dump
81
+
82
+
83
+ # 6. With two arguments
84
+ class Add < MethodHash
85
+ def mymethod(a,b)
86
+ a + b
87
+ end
88
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: methodhash
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Fredrik Johansson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-02 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A Hash for automatic storage of values obtained from a method defined by the user.
17
+ email: fredjoha@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - methodhash.gemspec
26
+ - lib/methodhash.rb
27
+ - README
28
+ - samples/samples.rb
29
+ has_rdoc: true
30
+ homepage: http://github.com/fredrikj/methodhash/tree/master
31
+ licenses: []
32
+
33
+ post_install_message:
34
+ rdoc_options: []
35
+
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: "0"
43
+ version:
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ requirements: []
51
+
52
+ rubyforge_project: methodhash
53
+ rubygems_version: 1.3.5
54
+ signing_key:
55
+ specification_version: 3
56
+ summary: methodhash
57
+ test_files: []
58
+