Class: Literate::Attempt
- Inherits:
- BasicObject
- Defined in:
- lib/y_support/literate.rb
Overview
Represents a commented attempt to perform a risky operation, which may result in errors. The operation code is supplied as a block. Method #comment defined by this class helps to increase the informative value of error messages.
Constant Summary collapse
- CONSTRUCT =
String construction closures are defined below.
-> string, prefix: '', postfix: '' do s = string.to_s if s.empty? then '' else prefix + s + postfix end end
- TRANSITIVE =
Hash of transitive verb forms.
::Hash.new do |_, key| "#{key}ing %s" end .update( is: "being %s", has: "having %s" )
- STATE =
Hash for construction of statements (error message parts).
::Hash.new do |ꜧ, key| "#{key} %s" end .update( is: "%s", has: "has %s" )
Instance Attribute Summary collapse
-
#__block__ ⇒ Object
readonly
Block that performs the attempt.
-
#__knowledge_base__ ⇒ Object
readonly
Returns the value of attribute knowledge_base.
-
#__subject__ ⇒ Object
readonly
An Attempt instance has 4 properties.
-
#__text__ ⇒ Object
readonly
NL description of the attempt.
Instance Method Summary collapse
-
#__circumstances__ ⇒ Object
Produces description of the circumstances, that is, concatenated descriptions of all facts known to the Attempt instance except those about the main subject of the attempt.
-
#__describe__(subject) ⇒ Object
Produces a description of the subject supplied to the method.
-
#__error_message__(error) ⇒ Object
Facilitating error messages is the main purpose of Literate.
-
#__run__(*args) ⇒ Object
Runs the attempt.
-
#initialize(subject: nil, text: nil, &block) ⇒ Attempt
constructor
Attempt constructor expects two parameters (:subject and :text) and one block.
-
#method_missing(symbol, *args) ⇒ Object
Method missing delegates all methods not recognized by Literate::Attempt class (which is a subclass of BasicObject) to the subject of the attempt.
-
#note(*subjects, **statements, &block) ⇒ Object
(also: #»)
Method #note is available inside the #try block.
-
#try(*args, &block) ⇒ Object
Inside the block, +#try method is delegated to the subject of the attempt.
Constructor Details
#initialize(subject: nil, text: nil, &block) ⇒ Attempt
Attempt constructor expects two parameters (:subject and :text) and one block. Argument of the :subject parameter is the main subject of the risky operation attempted inside the block. Argument of the :text parameter is the natural language textual description of the risky opration.
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/y_support/literate.rb', line 81 def initialize( subject: nil, text: nil, &block ) @__subject__ = subject @__text__ = text @__block__ = block # Knowledge base is a list of subjects and facts known # about them. @__knowledge_base__ = ::Hash.new do |hash, missing_key| hash[ missing_key ] = [ {} ] end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(symbol, *args) ⇒ Object
Method missing delegates all methods not recognized by Literate::Attempt class (which is a subclass of BasicObject) to the subject of the attempt.
183 184 185 |
# File 'lib/y_support/literate.rb', line 183 def method_missing symbol, *args __subject__.send symbol, *args end |
Instance Attribute Details
#__block__ ⇒ Object (readonly)
Block that performs the attempt.
71 72 73 |
# File 'lib/y_support/literate.rb', line 71 def __block__ @__block__ end |
#__knowledge_base__ ⇒ Object (readonly)
Returns the value of attribute knowledge_base.
73 74 75 |
# File 'lib/y_support/literate.rb', line 73 def __knowledge_base__ @__knowledge_base__ end |
#__subject__ ⇒ Object (readonly)
An Attempt instance has 4 properties.
70 71 72 |
# File 'lib/y_support/literate.rb', line 70 def __subject__ @__subject__ end |
#__text__ ⇒ Object (readonly)
NL description of the attempt.
72 73 74 |
# File 'lib/y_support/literate.rb', line 72 def __text__ @__text__ end |
Instance Method Details
#__circumstances__ ⇒ Object
Produces description of the circumstances, that is, concatenated descriptions of all facts known to the Attempt instance except those about the main subject of the attempt.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/y_support/literate.rb', line 213 def __circumstances__ # Start with all facts known to the Attempt instance. base = __knowledge_base__ # Ignore the facts about the main subject. circumstances = base.reject { |s, _| s == __subject__ } # Construct descriptive strings of the remaining facts. fact_strings = circumstances.map { |subject, _| subject, statements = __describe__( subject ) statements = statements.map { |verb, object| TRANSITIVE[ verb ] % object }.join( ', ' ) # Create the fact string. subject + CONSTRUCT.( statements, prefix: ' ' ) } # Concatenate the fact strings and return the result. return fact_strings.join( ', ' ) end |
#__describe__(subject) ⇒ Object
Produces a description of the subject supplied to the method.
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/y_support/literate.rb', line 189 def __describe__ subject # Start with the facts known about the subject. facts = __knowledge_base__[ subject ].dup # FIXME: I wonder what this method is *really* doing. # It seems that I wrote this library too quickly and didn't # bother with properly defining its list of facts. # I did not define what is a "fact", what is a "statement" # etc., I just go around using the words and hoping I will # understand it after myself later. I found it's quite hard. statements = if facts.last.is_a? ::Hash then facts.pop else {} end fs = facts.join ', ' if statements.empty? then return fs, statements else return facts.empty? ? subject.to_s : fs, statements end end |
#__error_message__(error) ⇒ Object
Facilitating error messages is the main purpose of Literate. This method is invoked when an error occurs inside the block run by Literate::Attempt instance and it constructs a verbose error message using the facts the Attempt instance knows.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/y_support/literate.rb', line 149 def error # Write the first part of the error message. part1 = "When trying #{__text__}" # Get the description of the main subject. subject, statements = __describe__( __subject__ ) # Write the 2nd part of the error message. part2 = CONSTRUCT.( subject, prefix: ' ' ) # Construct the descriptive string of the main subject. subject_description = statements.map { |verb, object| # Generate the statement string. STATE[ verb ] % object }.join ', ' # join the statement strings with commas # Write the third part of the error message. part3 = CONSTRUCT.( subject_description, prefix: ' (', postfix: ')' ) # Write the fourth part of the error message. part4 = CONSTRUCT.( __circumstances__, prefix: ', ' ) # Write the fifth part of the error message. part5 = ": #{error}" part6 = ['.', '!', '?'].include?( part5[-1] ) ? '' : '!' return [ part1, part2, part3, part4, part5, part6 ].join end |
#__run__(*args) ⇒ Object
Runs the attempt.
135 136 137 138 139 140 141 142 |
# File 'lib/y_support/literate.rb', line 135 def __run__ *args begin instance_exec *args, &__block__ rescue ::StandardError => error # Error has occured. Show time for Literate::Attempt. raise error, ( error ) end end |
#note(*subjects, **statements, &block) ⇒ Object Also known as: »
Method #note is available inside the #try block
note "Concatenation of Foo and Bar",
is: "FooBar",
has: "6 letters"
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/y_support/literate.rb', line 98 def note *subjects, **statements, &block if statements.empty? then # No statements were supplied to #note. subjects.each { |subject| # Fill in the knowledge base ... # FIXME: I wonder how the code here works. __knowledge_base__[ subject ].push_ordered subject } # FIXME: I wonder whether returning this is OK. return subjects end # Here, we know that variable statements is not empty. # If subjects variable is empty, assume main subject. subjects << __subject__ if subjects.empty? # Fill the knowledge base ... # FIXME: I wonder how the code here works. subjects.each { |subject| statements.each do |verb, object| __knowledge_base__[ subject ].push_named verb => object end } # Return the second element of the first statement. return statements.first[ 1 ] end |
#try(*args, &block) ⇒ Object
Inside the block, +#try method is delegated to the subject of the attempt.
175 176 177 |
# File 'lib/y_support/literate.rb', line 175 def try *args, &block __subject__.try *args, &block end |