Class: Computable
- Inherits:
-
Object
- Object
- Computable
- Defined in:
- lib/computable.rb,
lib/computable/version.rb
Defined Under Namespace
Classes: Error, InvalidFormat, RecursionDetected, UndefinedValue, Variable
Constant Summary collapse
- Unknown =
This is a special value to mark a variable to be computed.
Object.new
- VERSION =
"0.1.0"- @@debug =
false
Class Method Summary collapse
- .calc_value(name, format = nil, params = {}, &block) ⇒ Object
- .computable_debug ⇒ Object
- .computable_debug=(v) ⇒ Object
- .input_value(name, format = nil, params = {}) ⇒ Object
- .verify_format(name, value, format) ⇒ Object
Instance Method Summary collapse
- #computable_display_dot(params = {}) ⇒ Object
- #computable_to_dot(params = {}) ⇒ Object
-
#initialize ⇒ Computable
constructor
A new instance of Computable.
Constructor Details
#initialize ⇒ Computable
Returns a new instance of Computable.
122 123 124 125 |
# File 'lib/computable.rb', line 122 def initialize @variables = {} @caller = nil end |
Class Method Details
.calc_value(name, format = nil, params = {}, &block) ⇒ Object
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/computable.rb', line 134 def self.calc_value name, format=nil, params={}, &block freeze = params.delete(:freeze){ true } raise ArgumentError, "invalid params #{params.inspect}" unless params.empty? calc_method_id = "calc_#{name}".intern define_method(calc_method_id, &block) calc_method2_id = "calc_#{name}_with_tracking".intern define_method(calc_method2_id) do |v| begin v.value_calced = true @caller, old_caller = v, @caller begin puts "do calc #{v.inspect}" if @@debug res = send(calc_method_id) Computable.verify_format(name, res, format) res.freeze if freeze res ensure @caller = old_caller end end end define_method("#{name}=") do |value| Computable.verify_format(name, value, format) v = @variables[name] puts "set #{name}: #{value.inspect} #{v.inspect}" if @@debug v = @variables[name] = Variable.new(name, method(calc_method2_id)) unless v unless v.value == value v.expire_value v.expired_from.clear v.used_for.clear value.freeze if freeze v.value = value end v.value_calced = false end define_method(name) do v = @variables[name] puts "called #{name} #{v.inspect}" if @@debug v = @variables[name] = Variable.new(name, method(calc_method2_id)) unless v if @caller v2 = v.used_for[@caller.name] if v2 if v.value==Unknown && v2.value==Unknown && v.value_calced && v2.value_calced raise RecursionDetected, "#{v2.name} depends on #{name}, but #{name} could not be computed without #{v2.name}" end else v.used_for[@caller.name] = @caller end end v.recalc_value v.value = v.calc! if v.value==Unknown v.value end end |
.computable_debug ⇒ Object
86 87 88 |
# File 'lib/computable.rb', line 86 def self.computable_debug @@debug end |
.computable_debug=(v) ⇒ Object
83 84 85 |
# File 'lib/computable.rb', line 83 def self.computable_debug=(v) @@debug = v end |
.input_value(name, format = nil, params = {}) ⇒ Object
197 198 199 200 201 |
# File 'lib/computable.rb', line 197 def self.input_value name, format=nil, params={} calc_value name, format, params do raise UndefinedValue, "input variable '#{name}' is not assigned" end end |
.verify_format(name, value, format) ⇒ Object
128 129 130 131 132 |
# File 'lib/computable.rb', line 128 def self.verify_format(name, value, format) if format && value!=Unknown && !(format === value) raise InvalidFormat, "variable '#{name}': value #{value.inspect} is not in format #{format.inspect}" end end |
Instance Method Details
#computable_display_dot(params = {}) ⇒ Object
90 91 92 93 94 |
# File 'lib/computable.rb', line 90 def computable_display_dot(params={}) IO.popen("dot -Tpng | display -", "w") do |fd| fd.puts computable_to_dot(params) end end |
#computable_to_dot(params = {}) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/computable.rb', line 96 def computable_to_dot(params={}) rankdir = params.delete(:rankdir){ "TB" } multiline = params.delete(:multiline){ true } raise ArgumentError, "invalid params #{params.inspect}" unless params.empty? dot = "digraph #{self.class.name.inspect} {\n" dot << "graph [ dpi = 45, rankdir=#{rankdir} ];\n" @variables.each do |name, v| col = case when !v.value_calced then "color = red," when !v.used_for.empty? then "color = green," else "color = blue," end label = if multiline "#{name.to_s.gsub("_","\n")}\n(#{v.count})" else "#{name.to_s} (#{v.count})" end dot << "#{name.to_s.inspect} [#{col} label=#{label.inspect}];\n" v.used_for.each do |name2, v2| dot << "#{name.to_s.inspect} -> #{name2.to_s.inspect};\n" end end dot << "}\n" end |