methodhash 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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
+