Class: CodeHandler
Overview
A code handler continualy considers how to extend the complexity of a method in a custom class given the intial starting methods already availble within the class.
It also can refactor the code into separate methods thereby reusing the same functionality.
Essentially it just tries to create as many uniquely new variables as it can. Note they are consider unique if the process to create them is new, NOT whether or not there value is new.
Constant Summary collapse
- @@CODE_HANDLER_ID =
0
Instance Attribute Summary collapse
-
#default_structures ⇒ Object
writeonly
Sets the attribute default_structures.
-
#runtime_methods ⇒ Object
readonly
Returns the value of attribute runtime_methods.
Class Method Summary collapse
Instance Method Summary collapse
- #class_name ⇒ Object
-
#initialize(runtime_methods = [], structures = nil) ⇒ CodeHandler
constructor
A new instance of CodeHandler.
-
#itterate(count = 1, additional_available = []) ⇒ Object
Returns an array of method instances containing various numbers of statements.
-
#write ⇒ Object
Returns a string that prints out how the dynamic code for the code handler currently looks.
Constructor Details
#initialize(runtime_methods = [], structures = nil) ⇒ CodeHandler
Returns a new instance of CodeHandler.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/CodeHandler.rb', line 21 def initialize(runtime_methods=[],structures=nil) @runtime_methods = runtime_methods @entrance_method = create_entrance_method @code_handler_id = @@CODE_HANDLER_ID @@CODE_HANDLER_ID += 1 # These are the default statement structures if non-are supplied @default_structures = [ DeclareVariableAsVariableStructure.new, StatementStructure2.new(StatementStructure2.declared_runtime_method), StatementStructure2.new(StatementStructure2.declared_array), StatementStructure2.new(StatementStructure2.declared_string_addition), DeclareNewInstanceStructure.new(MethodUsageClass.new,RuntimeMethodClass.new) ] # If structures are supplied the overwrite the default structures @default_structures = structures unless structures.nil? end |
Instance Attribute Details
#default_structures=(value) ⇒ Object (writeonly)
Sets the attribute default_structures
17 18 19 |
# File 'lib/CodeHandler.rb', line 17 def default_structures=(value) @default_structures = value end |
#runtime_methods ⇒ Object (readonly)
Returns the value of attribute runtime_methods.
16 17 18 |
# File 'lib/CodeHandler.rb', line 16 def runtime_methods @runtime_methods end |
Class Method Details
.reset_global_id ⇒ Object
232 233 234 235 236 237 238 |
# File 'lib/CodeHandler.rb', line 232 def self.reset_global_id #http://www.zenspider.com/Languages/Ruby/QuickRef.html unless $".include?('test/unit.rb') StandardLogger.log 'WARNING: Resetting variable id, this should only be done for tests' end @@CODE_HANDLER_ID = 0 end |
Instance Method Details
#class_name ⇒ Object
240 241 242 |
# File 'lib/CodeHandler.rb', line 240 def class_name return "RuntimeCodeHandler"+@code_handler_id.to_s end |
#itterate(count = 1, additional_available = []) ⇒ Object
Returns an array of method instances containing various numbers of statements.
-
At this point we are creating a statement to go straight into a method or into a nested statement. First we find all the available variables in the context. For this to work the variables should be saved with a scope. At this point it isn’t concerning it’s self with the dependencies for the variable. It does however have to take into consideration scope. As such every nested statement maintains an array of it’s level e.g. [5,7] for a two level nested statement. This would mean that varibles with a scope level of 5 or 7 would be valid consideration.
-
Next using the variables available to it it constructs a number of different statements.
-
From this statement it needs to work backwards to construct the full method. It does this by finding all the dependencies that have the same scope level. After that has been done, if finds and adds all the dependcies on the other scope level.
-
With the method constructed the value for the new variable can be asscertained. The asscertained value gets added to available array. Also if a variable is overwritten within the nested statement then its value is included with a scope value outside the nested statement. Specifically a scope level the same as the variable that was overridden. The variable simple has a depencey on the nested statement. This allows it to rebuild the statements in the correct order. It can then check the scopes and wrap the nested statement accordingly.
91 92 93 94 95 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 121 122 123 124 125 126 127 128 129 130 131 132 133 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 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/CodeHandler.rb', line 91 def itterate(count=1,additional_available=[]) # Create an array to contain the vessels currently available initial_copied_method = @entrance_method.copy initial_copied_method.clear vessels = [initial_copied_method] # Create the array to contain the available variables and the initial runtime method calls available = [] available += additional_available @runtime_methods.each {|x| available += x.callable_combinations} # Set the scope id for all the method calls available.each {|x| x.scope_id = initial_copied_method.scope_id} # Maintains all the statements and their dependencies dependencies = StatementDependencies.new # Completed methods results = [] # Itterate over the number of times specified count.times do |i| # Keep track of the newly created variables newly_created_variable = [] # Keeps track of newly created vessels newly_created_vessels = [] # For each vessel create appropriate statements vessels.each do |vessel| # Find potential new statements available to the current vessel new_statement_results = find_possible_new_statements(vessel,available,dependencies) # Find the statement dependencies for each statement new_statement_results.each do |y| # Create the vessel for the new statement new_vessel = vessel.copy # Create a runtime method with the statement and all the dependencies copied_method = build_minimalist_method(@entrance_method,y,dependencies) # Realise the generated method begin realised_method = copied_method.realise2(ParametersContainer.new,@runtime_methods) rescue ImproperStatementUsageError => e # TODO I have rejected statements "var = <#statement_variable>.declare_variable" if the statement # variable doesn't represent a declaration statement. I don't know if this is the right way to # do things. It might be better to return a NilVariable or prevent it from ever being created. # TODO I should check this is logged StandardLogger.instance.warning('Method rejeceted') StandardLogger.instance.warning(e) next end results.push(realised_method) # TODO I should determine the nature of the statement and then # determine the new variables available. # - I should maybe save structures with statements. raise StandardError.new('Statement type has not defined for this statement') if y.statement_type.nil? # Determine the id of the statement that declares the value #case(y.statement_type) # when StatementStructure::DECLARATION_STATEMENT if((y.statement_type == StatementStructure::MODIFYING_STATEMENT)or(y.statement_type == StatementStructure::DECLARATION_STATEMENT)) #declared_variable_id = y.created_variable.variable_id variable_uniq_id = y.created_variable.uniq_id # Find the value of the variable within the realised method and set it's scope #resulting_variable = realised_method.find_variable(declared_variable_id) resulting_variable = realised_method.find_variable(variable_uniq_id) if y.kind_of?(BlockStatement) resulting_variable.scope_id = y.scope_id resulting_variable.clear else resulting_variable.scope_id = vessel.scope_id end newly_created_variable.push(resulting_variable) #new_vessel = realised_method.find_statement_that_declares_variable(declared_variable_id) # TODO Check this works with uniq_id new_vessel = realised_method.find_statement_that_created_variable(variable_uniq_id) # Find the statement from the typed method that declares the variable # NOTE I wonder if it would be quicker and safe to add the realised statement here #declaring_statement = realised_method.find_statement_that_declares_variable(declared_variable_id) # TODO Check this works with uniq_id declaring_statement = realised_method.find_statement_that_created_variable(variable_uniq_id) dependencies.push(declaring_statement) # If the new statement was a nested statement then add as vessel if y.kind_of?(BlockStatement) new_vessels_scope = [new_vessel.scope_id] new_vessels_scope += vessel.scope new_vessel.scope = new_vessels_scope new_vessel.clear newly_created_vessels.push(new_vessel) end # when StatementStructure::MODIFYING_STATEMENT: # # exit # # Need to save modified statement; # StandardLogger.instance.warning('I think I need to treat modifying statements as if they declare new variables') # # # TODO I'm not certain this isn't going to add loads of statement # StandardLogger.instance.info('Statement ID: '+y.statement_id.to_s) # StandardLogger.instance.info(': '+y.write) # # # Adding the statement the newly modified statement # dependencies.push(realised_method.select {|stment| stment.statement_id == y.statement_id}.first) # elsif(StatementStructure::USAGE_STATEMENT) else raise StandardError.new('Unknown statement_type "'+y.statement_type+'" "'+y.write+'"') end end end # Add the new variables to available list # TODO newly_created_variable is an array - it should be newly_created_variables available += newly_created_variable # Add the new vessel to the list vessels += newly_created_vessels end return results end |
#write ⇒ Object
Returns a string that prints out how the dynamic code for the code handler currently looks.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/CodeHandler.rb', line 43 def write dynamic_code = "class #{class_name}"+"\n" # Include each of the avaialble runtime methods @runtime_methods.each do |x| dynamic_code += x.write(ParametersContainer.new,1) end # Now add the entrance method dynamic_code += @entrance_method.write(ParametersContainer.new,1) dynamic_code += "end" return dynamic_code end |