conditions 0.0.2.alpha

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ nbproject/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in conditions.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2011, André Gawron
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ - Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ - Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ - The names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
19
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24
+ OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.rdoc ADDED
@@ -0,0 +1,37 @@
1
+ = Conditions
2
+
3
+ Conditions is some kind of low-level condition-based
4
+ event-handler suitable for different kind of uses.
5
+ Typical use is error handling. it's ported from LISP's Condition System:
6
+
7
+ http://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html
8
+
9
+ THIS IS HIGHLY ALPHA! DO NOT USE IN PRODUCTION!
10
+ (but syntax is most likely not going to change)
11
+
12
+ For more information, read covering blog posts on:
13
+
14
+ http://www.andre-gawron.de/123/the-diversity-of-error-handling
15
+
16
+ http://www.andre-gawron.de/187/road-to-condition
17
+
18
+ == Patching
19
+
20
+ It's currently extending the Object class. Why? Kinda easy.
21
+ I don't want to write Conditions::handle (etc).
22
+
23
+ The Object class is patched as soon as Conditions are required.
24
+ I'm lookin into actually check before patching if there are other
25
+ methods already in the Object class and probably not allow
26
+ patching then. But that's for the future, it's alpha, right?
27
+
28
+ == I'd like to patch and / or help maintain Conditions. How can I?
29
+
30
+ Are you sure? Ok, feel free to ...
31
+
32
+ * Fork the project: http://github.com/melkon/conditions
33
+ * Make your feature addition or bug fix.
34
+
35
+ == Copyright
36
+
37
+ Copyright (c) 2011 André Gawron. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,19 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "conditions/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "conditions"
6
+ s.version = Conditions::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["André Gawron"]
9
+ s.email = ["andre@ziemek.de"]
10
+ s.homepage = "https://github.com/melkon/conditions"
11
+ s.summary = %q{Implements the Lisp's condition system in Ruby}
12
+ s.description = %q{Implements the Lisp's condition system in Ruby}
13
+ s.license = 'BSD'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,6 @@
1
+ yes
2
+ no
3
+ no
4
+ no
5
+ no
6
+ yes
@@ -0,0 +1,72 @@
1
+ require "conditions"
2
+
3
+ class MalformedLogEntryError < Condition ; end
4
+
5
+ bind :NoticeSignaled => lambda { invoke :Suppress}
6
+
7
+ p (bind :NoticeSignaled => lambda { invoke :Suppress } do
8
+ "block value is returning!"
9
+ end)
10
+
11
+ def parse_log_entry text
12
+
13
+ if !well_formed? text then
14
+
15
+ restart :UseValue => proc { |value| text = value },
16
+ :ReparseEntry => proc { |fixed| text = parse_log_entry fixed } do
17
+
18
+ error MalformedLogEntryError
19
+
20
+ end
21
+
22
+ end
23
+
24
+ text
25
+
26
+ end
27
+
28
+ def parse_log_file file
29
+
30
+ File.open(file).each do |line|
31
+
32
+ entry = (restart :SkipLogEntry => lambda { nil } do
33
+ parse_log_entry line
34
+ end)
35
+
36
+ yield entry if entry
37
+
38
+ end
39
+
40
+ end
41
+
42
+ def log_analyzer
43
+
44
+ bind :ConditionNotDefined => lambda { invoke :Define },
45
+ :MalformedLogEntryError => lambda { invoke :UseValue, "failed\n" } do
46
+ find_logs do |log|
47
+ analyze_log log
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ def analyze_log log
54
+ parse_log_file log do |entry|
55
+ analyze_entry entry
56
+ end
57
+ end
58
+
59
+ def well_formed? text
60
+ "yes\n" == text ? true : false
61
+ end
62
+
63
+ def analyze_entry entry
64
+ p entry
65
+ end
66
+
67
+ def find_logs
68
+ yield "./log"
69
+ yield "./another-log"
70
+ end
71
+
72
+ log_analyzer
data/example/log ADDED
@@ -0,0 +1,5 @@
1
+ yes
2
+ yes
3
+ no
4
+ no
5
+ yes
data/example/newfile ADDED
File without changes
data/lib/conditions.rb ADDED
@@ -0,0 +1,16 @@
1
+ # main api
2
+ require "conditions/signals"
3
+ require "conditions/handles"
4
+ require "conditions/restarts"
5
+
6
+ # base condition classes
7
+ require "conditions/definitions/defaults"
8
+
9
+ # helper functions and exception definitions
10
+ require "conditions/lib/helpers"
11
+ require "conditions/lib/exceptions"
12
+
13
+ # remove this and the puppy will cry
14
+ class Object
15
+ include Conditions
16
+ end
@@ -0,0 +1,38 @@
1
+ class Condition
2
+
3
+ attr_reader :dynamic, :trace, :message, :restarts
4
+
5
+ def initialize message = nil
6
+
7
+ @message = message
8
+
9
+ @trace = Kernel.caller
10
+ @dynamic = false
11
+ @restarts = Utils::Handler::get_restarts
12
+
13
+ end
14
+
15
+ end
16
+
17
+ class ConditionDynamic < Condition
18
+
19
+ def initialize *params
20
+
21
+ super params
22
+
23
+ @params = params
24
+ @dynamic = true
25
+
26
+ end
27
+
28
+ def get key
29
+ @params[key]
30
+ end
31
+
32
+ end
33
+
34
+ class DynamicConditionCreation < Condition ; end
35
+ class ConditionNotDefined < Condition ; end
36
+ class NoDynamicConditionAllowed < Condition ; end
37
+
38
+ class NoticeSignaled < Condition ; end
@@ -0,0 +1,143 @@
1
+ module Conditions
2
+
3
+ #
4
+ # handles a signaled condition
5
+ #
6
+ # handles a condition signaled by #signal or any other signaling method
7
+ # by registering handlers for given conditions.
8
+ #
9
+ # if a handler matches a condition, it will be executed and after that,
10
+ # the stack will be unwound to the point where the latest #handle registered
11
+ # a handler for given condition returning the value of the executed handler.
12
+ #
13
+ # @param *conditions conditions which shall be catched by #handle,
14
+ # @param &block block which will be executed normally if no condition will be signaled
15
+ #
16
+ # @return return value of &block
17
+ # @return if a condition is catched, the return value of the registered handler
18
+ #
19
+ # @raises ConditionHandled if the catched condition doesnt belong to current block
20
+ #
21
+ # @see #parse_handlers for syntax information on *conditions
22
+ #
23
+ def handle *conditions, &block
24
+
25
+ conditions = Utils::parse_handlers conditions
26
+
27
+ conditions.each do |condition|
28
+ Utils::Handler::set(:condition, condition.merge!(:raise => true))
29
+ end
30
+
31
+ value = begin
32
+ block.call
33
+ rescue Exception::ConditionHandled => ex
34
+
35
+ # if condition doesnt belong to this block,
36
+ # continue unwinding the stack
37
+ if !Utils::find_handler(ex.condition[:name], conditions) then
38
+ raise Exception::ConditionHandled, :value => ex.value, :condition => ex.condition
39
+ end
40
+
41
+ ex.value
42
+
43
+ end
44
+
45
+ conditions.each do |condition|
46
+ Utils::Handler::unset(:condition, condition)
47
+ end
48
+
49
+ value
50
+
51
+ end
52
+
53
+ #
54
+ # binds a handler to a condition
55
+ #
56
+ # #bind works similiar to #handle but instead of unwinding the stack,
57
+ # #bind returns the value of the last called handler.
58
+ #
59
+ # caveat:
60
+ #
61
+ # *if* there's a condition bound by #handle in the upper callstack
62
+ # *and* the same condition is bound by #bind inside of this #handle,
63
+ # the system will unwind the stack to #handle - but the condition's handler
64
+ # bound by #bind will be executed and properly unregistered.
65
+ #
66
+ # @param *conditions conditions which shall be bound by #bind,
67
+ # @param &block block which will be executed normally if no condition will be signaled
68
+ #
69
+ # @return return value of &block
70
+ # @return if a condition is signaled and bound by #bind, it returns value of the last registered handler
71
+ #
72
+ # @see #parse_handlers for syntax information on *conditions
73
+ #
74
+ def bind *conditions, &block
75
+
76
+ conditions = Utils::parse_handlers conditions
77
+
78
+ conditions.each do |condition|
79
+ Utils::Handler::set(:condition, condition.merge!(:raise => false))
80
+ end
81
+
82
+ value = true
83
+ if block_given? then
84
+
85
+ value = begin
86
+
87
+ # tmp save the value of the callback
88
+ # and return it after the conditions were unset
89
+ value = block.call
90
+
91
+ conditions.each do |condition|
92
+ Utils::Handler::unset(:condition, condition)
93
+ end
94
+
95
+ value
96
+
97
+ # it is possible that a Condition has a handler registered by #handle
98
+ # and therefore will unwind the stack. but if a handler bound by #bind
99
+ # and #bind is used with a block, the bound handler will not be unregistered.
100
+ # therefore, catch the exception intended for #handle
101
+ # unregister the handler registered by #bind
102
+ # and rethrow the exception again to reach the proper #handle
103
+ rescue Exception::ConditionHandled => ex
104
+
105
+ conditions.each do |condition|
106
+ Utils::Handler::unset(:condition, condition)
107
+ end
108
+
109
+ raise Exception::ConditionHandled, :value => ex.value, :condition => ex.condition
110
+
111
+ end
112
+
113
+ end
114
+
115
+ value
116
+
117
+ end
118
+
119
+ #
120
+ # unregisters a bound condition
121
+ #
122
+ # if bind is used without a block,
123
+ # #unbind is used to unregister the condition's handler
124
+ #
125
+ # @param *conditions conditions which shall be unregistered by #unbind,
126
+ #
127
+ # @return [Boolean] true
128
+ #
129
+ # @see #parse_handlers for syntax information on *conditions
130
+ #
131
+ def unbind *conditions
132
+
133
+ conditions = Utils::parse_handlers conditions
134
+
135
+ conditions.each do |condition|
136
+ Exception::Handler::unset(:condition, condition)
137
+ end
138
+
139
+ true
140
+
141
+ end
142
+
143
+ end
@@ -0,0 +1,35 @@
1
+ module Conditions::Exception
2
+
3
+ class ConditionNotHandledError < StandardError ; end
4
+ class ConditionHandled < StandardError
5
+
6
+ attr_reader :value, :condition
7
+
8
+ def initialize info
9
+
10
+ super info[:value]
11
+
12
+ @value = info[:value]
13
+ @condition = info[:condition]
14
+
15
+ end
16
+
17
+ end
18
+
19
+ class RestartNotFoundError < StandardError ; end
20
+ class RestartHandled < StandardError
21
+
22
+ attr_reader :value, :restart
23
+
24
+ def initialize info
25
+
26
+ super info[:value]
27
+
28
+ @value = info[:value]
29
+ @restart = info[:restart]
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,226 @@
1
+ module Conditions::Utils
2
+
3
+ class Handler
4
+
5
+ @@types = {:condition => {},
6
+ :restart => {}}
7
+
8
+ #
9
+ # yields every registered condition for given type
10
+ #
11
+ # opts:
12
+ # :reverse => true|false [default: true] LIFO or FIFO of yielded handlers
13
+ #
14
+ # @param [String, Symbol] supported types: :condition, :restart
15
+ # @param [String, Symbol] name of the condition
16
+ # @param [Hash] opts current available: :reverse => true
17
+ #
18
+ def self.get(type, condition_name, opts = {})
19
+
20
+ condition_name = Utils::normalize(condition_name)
21
+
22
+ if (!@@types[type].has_key?(condition_name)) or (@@types[type][condition_name].empty?)
23
+ return nil
24
+ end
25
+
26
+ opts[:reserve] = true unless opts[:reserve] === false
27
+
28
+ if opts[:reserve] === true
29
+ direction = :reverse_each
30
+ else
31
+ direction = :each
32
+ end
33
+
34
+ @@types[type][condition_name].send(direction) do |condition|
35
+
36
+ condition[:name] = condition_name
37
+
38
+ yield condition
39
+
40
+ end
41
+
42
+ end
43
+
44
+ def self.get_restarts()
45
+ return @@types[:restarts];
46
+ end
47
+
48
+ def self.get_handlers()
49
+ return @@types[:condition];
50
+ end
51
+
52
+ def self.set(type, condition)
53
+
54
+ condition[:name] = Utils::normalize(condition[:name])
55
+
56
+ @@types[type][condition[:name]] = [] unless @@types[type][condition[:name]]
57
+ @@types[type][condition[:name]].push({:block => condition[:block],
58
+ :raise => condition[:raise]})
59
+
60
+ end
61
+
62
+ def self.unset(type, condition)
63
+
64
+ condition[:name] = Utils::normalize(condition[:name])
65
+
66
+ @@types[type][condition[:name]].each_with_index do |saved_condition, index|
67
+
68
+ if saved_condition[:block] == condition[:block]
69
+
70
+ # completely delete the restart-entry if no block is given anymore
71
+ if 2 >@@types[type][condition[:name]].size then
72
+ @@types[type].delete(condition[:name])
73
+ else
74
+ @@types[type][condition[:name]].delete_at(index)
75
+ end
76
+
77
+ # unset only one condition
78
+ return true
79
+
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ #
89
+ # parses magically the correct handlers / restarts
90
+ #
91
+ # #parse_handlers takes a hash as an argument and tries to identify
92
+ # the handlers / restarts and their callbacks. the syntax is the same for both.
93
+ #
94
+ # the simpliest is:
95
+ #
96
+ # :HandlerName => callback[, ...]
97
+ #
98
+ # class names are also supported:
99
+ #
100
+ # HandlerNAme => callback[, ...]
101
+ #
102
+ # class names as well as symbol will be casted to strings internally.
103
+ #
104
+ # currently, the callback has to be a lambda or
105
+ # a proc function to work within the condition system.
106
+ #
107
+ # it's also possible to define multiple handlers / restarts with the same callback:
108
+ #
109
+ # :HandlerName1, :HandlerName2, {:HandlerName3 => callback}[, ...]
110
+ #
111
+ # now let's mix everything together:
112
+ #
113
+ # :HandlerName => callback, HandlerName1, {:HandlerName2 => callback}, :HandlerName3 => callback
114
+ #
115
+ # why does this work?
116
+ #
117
+ # it's a lot of magic with hashes, since the #handle and #restart functions are using the * operator.
118
+ # this way, the parameters are wrapped in a Hash and can be magically transformed.
119
+ #
120
+ # @param [Hash] handlers a multidimensional Hash
121
+ #
122
+ # @return [Hash] a structured hash {{:name => :HandlerName, :block => callback}[, ...}}
123
+ #
124
+ def self.parse_handlers(handlers)
125
+
126
+ without_proc = []
127
+ parsed = []
128
+
129
+ handlers.each do |handler|
130
+
131
+ if handler.is_a? Hash
132
+
133
+ handler.each do |handler_name, handler_proc|
134
+
135
+ without_proc.each do |handler_name|
136
+ parsed.push(:name => handler_name, :block => handler_proc)
137
+ end
138
+
139
+ parsed.push(:name => handler_name, :block => handler_proc)
140
+
141
+ end
142
+
143
+ without_proc.clear
144
+
145
+ else
146
+
147
+ without_proc.push(handler)
148
+
149
+ end
150
+
151
+ end
152
+
153
+ parsed
154
+
155
+ end
156
+
157
+ #
158
+ # creates a condition object
159
+ #
160
+ # creates a condition object of given conditon_name symbol or string-class
161
+ # if the requested condition_name is not a existing class,
162
+ # #generate_condition registers a restart offering to dynamically create class.
163
+ # currently, the new class will be created in the module Conditions.
164
+ #
165
+ # this condition class inherits the class ConditionDynamic.
166
+ #
167
+ # @param [String, Symbol] condition_name the condition class' name to instance. it must start with an upper case letter!
168
+ # @param *params parameters forwarded to the condition class' constructor
169
+ #
170
+ # @return [Condition] object of the demanded condition class
171
+ #
172
+ # @error :ConditionNotDefined if requested condition class does not exist
173
+ #
174
+ # @restart :Define creates a dynamic condition named like condition_name
175
+ #
176
+ def self.generate_condition(condition_name, *params)
177
+
178
+ if not condition_name.kind_of?(Class)
179
+
180
+ if !Conditions.const_defined? condition_name then
181
+ restart :WriteToFile => lambda { p "will be implemented anytime soon" },
182
+ :Define => lambda { Conditions::const_set(condition_name, Class.new(ConditionDynamic))
183
+ notice :DynamicConditionCreation, "#{condition_name} dynamically created" } do
184
+
185
+ error :ConditionNotDefined, condition_name
186
+ end
187
+ end
188
+
189
+ condition_name = Conditions::const_get(condition_name)
190
+
191
+ end
192
+
193
+ condition_name.new(*params)
194
+
195
+ end
196
+
197
+ #
198
+ # finds a handler in the given hash
199
+ #
200
+ # @param [String, Symbol] the handler / restart to find
201
+ # @param [Hash] a hash of handlers / restarts: {{:name => :Handlername}[, ...]}
202
+ #
203
+ # @return [Boolean] true if found
204
+ # @return [Boolean] false if not
205
+ #
206
+ def self.find_handler(name, handlers)
207
+
208
+ name = Utils::normalize(name)
209
+
210
+ handlers.each do |handler|
211
+
212
+ if name == handler[:name]
213
+ return true
214
+ end
215
+
216
+ end
217
+
218
+ false
219
+
220
+ end
221
+
222
+ def self.normalize(name)
223
+ return name.to_s
224
+ end
225
+
226
+ end
@@ -0,0 +1,76 @@
1
+ module Conditions
2
+
3
+ #
4
+ # register a possible restart-option
5
+ #
6
+ # register a possible restart-option
7
+ # which can be invoked by an condition handler using #invoke
8
+ #
9
+ # since its possible to access the method's scope
10
+ # you can actually modify the method's behaviour from a handler
11
+ # which can be pretty dangerous but also very rewarding.
12
+ #
13
+ # if no restart was invoked, it returns the value of the block
14
+ # otherwise, it returns the value of invoked restart
15
+ #
16
+ # @param *restarts register restarts
17
+ # @param &block the code to execute normally
18
+ #
19
+ # @return value of the &block
20
+ # @return value of the invoked restart
21
+ #
22
+ # @raises RestartHandled if the catched restart doesnt belong to this block
23
+ #
24
+ # @see #parse_handlers for syntax information on *conditions
25
+ #
26
+ def restart *restarts, &block
27
+
28
+ restarts = Utils::parse_handlers restarts
29
+
30
+ restarts.each { |restart| Utils::Handler::set(:restart, restart)}
31
+
32
+ value = begin
33
+ block.call
34
+ rescue Exception::RestartHandled => ex
35
+
36
+ # if restart doesnt belong to this block,
37
+ # continue unwinding the stack
38
+ if !Utils::find_handler(ex.restart, restarts) then
39
+ raise Exception::RestartHandled, :value => ex.value, :restart => ex.restart
40
+ end
41
+
42
+ ex.value
43
+
44
+ end
45
+
46
+ restarts.each { |restart| Utils::Handler::unset(:restart, restart)}
47
+
48
+ value
49
+
50
+ end
51
+
52
+ #
53
+ # invokes a registered restart
54
+ #
55
+ # #invoke checks if a restart with restart_name was registered
56
+ # and calls it if found.
57
+ #
58
+ # @param [String] restart_name the restart which shall be invoked
59
+ # @param *params parameters which are needed by the restart
60
+ #
61
+ # @raises RestartHandled if a invoked restart is called
62
+ # @raises RestartNotFoundError if a demanded restart was not found
63
+ #
64
+ # @see #parse_handlers for syntax information on *conditions
65
+ #
66
+ def invoke restart_name, *params
67
+
68
+ Utils::Handler::get(:restart, restart_name) do |restart|
69
+ raise Exception::RestartHandled, :value => restart[:block].call(*params), :restart => restart_name
70
+ end
71
+
72
+ raise Exception::RestartNotFoundError, restart_name
73
+
74
+ end
75
+
76
+ end
@@ -0,0 +1,95 @@
1
+ module Conditions
2
+
3
+ #
4
+ # calls the registered handler for given condition
5
+ #
6
+ # if the registered handler is established using #handle,
7
+ # the call to #signal will not return and raise an exception instead.
8
+ #
9
+ # if it's established using bind, #signal will return normally with
10
+ # the handler's returned value.
11
+ #
12
+ # @param [Symbol] conditon_name the condition to signal
13
+ # @param *params additional information wich will be directly passed
14
+ # to the condition's constructor
15
+ #
16
+ # @return value the return value of the called handler.
17
+ #
18
+ # @raises ConditionHandled if a handler is established with #handle
19
+ #
20
+ def signal condition_name, *params
21
+
22
+ value = nil
23
+
24
+ condition = Utils::generate_condition condition_name, *params
25
+
26
+ Utils::Handler::get :condition, condition_name do |handler|
27
+
28
+ value = case handler[:block].arity
29
+ when 0 then handler[:block].call
30
+ when 1 then handler[:block].call condition
31
+ when 2 then handler[:block].call condition, value
32
+ end
33
+
34
+ raise(Exception::ConditionHandled, :value => value, :condition => handler) if handler[:raise]
35
+
36
+ end
37
+
38
+ value
39
+
40
+ end
41
+
42
+ #
43
+ # errors a condition
44
+ #
45
+ # it's build on top of #signal but will raise an ConditionNotHandledError
46
+ # if #signal returns normally. This ensures that a condition errored using
47
+ # #error has to be handled by a condition handler with an non-local exit
48
+ # as it's done by using #handle.
49
+ #
50
+ # @param [Symbol] condition condition's name
51
+ # @param *params additional information wich will be directly passed
52
+ # to the condition's constructor
53
+ #
54
+ # @raises ConditionNotHandledError if the condition was not handled
55
+ #
56
+ def error condition, *params
57
+
58
+ signal condition, *params
59
+
60
+ raise Exception::ConditionNotHandledError, "condition #{condition} was not handled"
61
+
62
+ end
63
+
64
+ #
65
+ # notices a condition
66
+ #
67
+ # it's build on top of #signal and will print the given message
68
+ # it can be suppressed by invoking the restart :Suppress.
69
+ #
70
+ # since notice is calling #signal,
71
+ # the given condition can also be handled
72
+ #
73
+ # if no handler is bound to given condition, #notice returns normally.
74
+ #
75
+ # @param [Symbol] condition condition's name
76
+ # @param [String] message
77
+ #
78
+ # @return nil or bound handler's returned value
79
+ #
80
+ # @signal :NoticeSignaled if #notice got called.
81
+ #
82
+ # @restart :Suppress message will not be printed
83
+ #
84
+ def notice condition, message
85
+
86
+ restart :Suppress => lambda { nil } do
87
+ signal :NoticeSignaled, condition
88
+ print "Notice: #{message}"
89
+ end
90
+
91
+ signal condition
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,3 @@
1
+ module Conditions
2
+ VERSION = "0.0.2.alpha"
3
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: conditions
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: 6
5
+ version: 0.0.2.alpha
6
+ platform: ruby
7
+ authors:
8
+ - "Andr\xC3\xA9 Gawron"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-08-31 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: Implements the Lisp's condition system in Ruby
17
+ email:
18
+ - andre@ziemek.de
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - .gitignore
27
+ - Gemfile
28
+ - LICENSE
29
+ - README.rdoc
30
+ - Rakefile
31
+ - conditions.gemspec
32
+ - example/another-log
33
+ - example/example.rb
34
+ - example/log
35
+ - example/newfile
36
+ - lib/conditions.rb
37
+ - lib/conditions/definitions/defaults.rb
38
+ - lib/conditions/handles.rb
39
+ - lib/conditions/lib/exceptions.rb
40
+ - lib/conditions/lib/helpers.rb
41
+ - lib/conditions/restarts.rb
42
+ - lib/conditions/signals.rb
43
+ - lib/conditions/version.rb
44
+ homepage: https://github.com/melkon/conditions
45
+ licenses:
46
+ - BSD
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">"
62
+ - !ruby/object:Gem::Version
63
+ version: 1.3.1
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.8.5
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Implements the Lisp's condition system in Ruby
71
+ test_files: []
72
+