Class: Fast::ExperimentFile
- Inherits:
-
Object
- Object
- Fast::ExperimentFile
- Defined in:
- lib/fast/experiment.rb
Overview
it can easily spend days handling multiple one to one combinations, because of that, after the first round of replacements the algorithm goes replacing all winner solutions in the same shot. If it fails, it goes combining one to one.
Combines an Experiment with a specific file. It coordinates and regulate multiple replacements in the same file. Everytime it #run a file, it uses #partial_replace and generate a new file with the new content. It executes the Fast::Experiment#policy block yielding the new file. Depending on the policy result, it adds the occurrence to #fail_experiments or #ok_experiments. When all possible occurrences are replaced in isolated experiments, it ##build_combinations with the winner experiments going to a next round of experiments with multiple partial replacements until find all possible combinations.
Instance Attribute Summary collapse
-
#experiment ⇒ Object
readonly
Returns the value of attribute experiment.
-
#fail_experiments ⇒ Object
readonly
Returns the value of attribute fail_experiments.
-
#ok_experiments ⇒ Object
readonly
Returns the value of attribute ok_experiments.
Instance Method Summary collapse
-
#build_combinations ⇒ Object
Increase the ‘@round` by 1 to Fast::ExperimentCombinations#generate_combinations.
- #done! ⇒ Object
-
#experimental_filename(combination) ⇒ String
With a derived name with the combination number.
-
#failed_with(combination) ⇒ void
Track failed experiments to avoid run them again.
-
#initialize(file, experiment) ⇒ ExperimentFile
constructor
A new instance of ExperimentFile.
-
#ok_with(combination) ⇒ Object
Keep track of ok experiments depending on the current combination.
-
#partial_replace(*indices) ⇒ void
rubocop:disable Metrics/MethodLength.
- #run ⇒ Object
-
#run_partial_replacement_with(combination) ⇒ Object
Writes a new file with partial replacements based on the current combination.
- #search ⇒ String
- #search_cases ⇒ Array<Astrolabe::Node>
-
#write_experiment_file(combination, new_content) ⇒ Object
Write new file name depending on the combination.
Constructor Details
#initialize(file, experiment) ⇒ ExperimentFile
Returns a new instance of ExperimentFile.
247 248 249 250 251 252 253 254 |
# File 'lib/fast/experiment.rb', line 247 def initialize(file, experiment) @file = file @ast = Fast.ast_from_file(file) if file @experiment = experiment @ok_experiments = [] @fail_experiments = [] @round = 0 end |
Instance Attribute Details
#experiment ⇒ Object (readonly)
Returns the value of attribute experiment.
245 246 247 |
# File 'lib/fast/experiment.rb', line 245 def experiment @experiment end |
#fail_experiments ⇒ Object (readonly)
Returns the value of attribute fail_experiments.
245 246 247 |
# File 'lib/fast/experiment.rb', line 245 def fail_experiments @fail_experiments end |
#ok_experiments ⇒ Object (readonly)
Returns the value of attribute ok_experiments.
245 246 247 |
# File 'lib/fast/experiment.rb', line 245 def ok_experiments @ok_experiments end |
Instance Method Details
#build_combinations ⇒ Object
Increase the ‘@round` by 1 to Fast::ExperimentCombinations#generate_combinations.
338 339 340 341 342 343 344 345 346 |
# File 'lib/fast/experiment.rb', line 338 def build_combinations @round += 1 ExperimentCombinations.new( round: @round, occurrences_count: search_cases.size, ok_experiments: @ok_experiments, fail_experiments: @fail_experiments ).generate_combinations end |
#done! ⇒ Object
326 327 328 329 330 331 332 333 334 335 |
# File 'lib/fast/experiment.rb', line 326 def done! count_executed_combinations = @fail_experiments.size + @ok_experiments.size puts "Done with #{@file} after #{count_executed_combinations} combinations" return unless perfect_combination = @ok_experiments.last # rubocop:disable Lint/AssignmentInCondition puts 'The following changes were applied to the file:' `diff #{experimental_filename(perfect_combination)} #{@file}` puts "mv #{experimental_filename(perfect_combination)} #{@file}" `mv #{experimental_filename(perfect_combination)} #{@file}` end |
#experimental_filename(combination) ⇒ String
Returns with a derived name with the combination number.
262 263 264 265 266 267 |
# File 'lib/fast/experiment.rb', line 262 def experimental_filename(combination) parts = @file.split('/') dir = parts[0..-2] filename = "experiment_#{[*combination].join('_')}_#{parts[-1]}" File.join(*dir, filename) end |
#failed_with(combination) ⇒ void
This method returns an undefined value.
Track failed experiments to avoid run them again.
284 285 286 |
# File 'lib/fast/experiment.rb', line 284 def failed_with(combination) @fail_experiments << combination end |
#ok_with(combination) ⇒ Object
Keep track of ok experiments depending on the current combination. It keep the combinations unique removing single replacements after the first round.
273 274 275 276 277 278 279 280 |
# File 'lib/fast/experiment.rb', line 273 def ok_with(combination) @ok_experiments << combination return unless combination.is_a?(Array) combination.each do |element| @ok_experiments.delete(element) end end |
#partial_replace(*indices) ⇒ void
This method returns an undefined value.
rubocop:disable Metrics/MethodLength
Execute partial replacements generating new file with the content replaced.
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/fast/experiment.rb', line 298 def partial_replace(*indices) replacement = experiment.replacement new_content = Fast.replace_file experiment.expression, @file do |node, *captures| if indices.nil? || indices.empty? || indices.include?(match_index) if replacement.parameters.length == 1 instance_exec node, &replacement else instance_exec node, *captures, &replacement end end end return unless new_content write_experiment_file(indices, new_content) new_content end |
#run ⇒ Object
348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/fast/experiment.rb', line 348 def run while (combinations = build_combinations).any? if combinations.size > 1000 puts "Ignoring #{@file} because it has #{combinations.size} possible combinations" break end puts "#{@file} - Round #{@round} - Possible combinations: #{combinations.inspect}" while combination = combinations.shift # rubocop:disable Lint/AssignmentInCondition run_partial_replacement_with(combination) end end done! end |
#run_partial_replacement_with(combination) ⇒ Object
Writes a new file with partial replacements based on the current combination. Raise error if no changes was made with the given combination indices.
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
# File 'lib/fast/experiment.rb', line 365 def run_partial_replacement_with(combination) content = partial_replace(*combination) experimental_file = experimental_filename(combination) File.open(experimental_file, 'w+') { |f| f.puts content } raise 'No changes were made to the file.' if FileUtils.compare_file(@file, experimental_file) result = experiment.ok_if.call(experimental_file) if result ok_with(combination) puts "✅ #{experimental_file} - Combination: #{combination}" else failed_with(combination) puts "🔴 #{experimental_file} - Combination: #{combination}" end end |
#search ⇒ String
Returns from Fast::Experiment#expression.
257 258 259 |
# File 'lib/fast/experiment.rb', line 257 def search experiment.expression end |
#search_cases ⇒ Array<Astrolabe::Node>
289 290 291 |
# File 'lib/fast/experiment.rb', line 289 def search_cases Fast.search(experiment.expression, @ast) || [] end |
#write_experiment_file(combination, new_content) ⇒ Object
Write new file name depending on the combination
320 321 322 323 324 |
# File 'lib/fast/experiment.rb', line 320 def write_experiment_file(combination, new_content) filename = experimental_filename(combination) File.open(filename, 'w+') { |f| f.puts new_content } filename end |