diff --git a/lib/naming_normalizers/base.rb b/lib/naming_normalizers/base.rb new file mode 100644 index 0000000..899e3d1 --- /dev/null +++ b/lib/naming_normalizers/base.rb @@ -0,0 +1,55 @@ +module NamingNormalizers + class Base < Parser::TreeRewriter + include Mandate + + def initialize(code) + @code = code + @mapping = {} + end + + def call + buffer = Parser::Source::Buffer.new('', source: code) + builder = RuboCop::AST::Builder.new + ast = Parser::CurrentRuby.new(builder).parse(buffer) + rewrite(buffer, ast) + end + + def on_op_asgn(node) + # p "opasgn" + #node.pry + super + end + + def on_casgn(node) + # p "casgn" + #node.pry + super + end + + def on_defs(node) + # p "defs" + #node.pry + super + end + + def on_numblock(node) + # p "numblock" + #node.pry + super + end + + def handler_missing(node) + case node.type + # noop + when true, :str, :nil, :int + super + else + p "handler_missing" + #node.pry + end + end + + private + attr_reader :code, :mapping + end +end diff --git a/lib/naming_normalizers/method_locals.rb b/lib/naming_normalizers/method_locals.rb new file mode 100644 index 0000000..e9fdf2a --- /dev/null +++ b/lib/naming_normalizers/method_locals.rb @@ -0,0 +1,60 @@ +module NamingNormalizers + class MethodLocals < Base + + def initialize(code) + super(code) + + @method_name = nil + @methods_vars = {} + end + + %i[ + on_argument + on_const + on_var + on_vasgn + ].each do |method_name| + define_method method_name do |node| + replace_loc_name(node) + super(node) + end + end + + def on_def(node) + @method_name = node.loc.name.source + @methods_vars[@method_name] = {} + + super(node) + end + + def on_end(node) + node.pry + end + + def handler_missing(node) + super(node) + end + + def replace_loc_name(node) + replace(node.loc.name, placeholder_for(node.loc.name.source)) + end + + def replace_loc_selector(node) + replace(node.loc.selector, placeholder_for(node.loc.selector.source)) + end + + def placeholder_for(token) + # Return if we're outside of a method + return token unless instance_variable_defined?("@method_name") && @method_name + + # Get the vars for this method_naem + meth_vars = @methods_vars[@method_name] + + # Return if we have one + return meth_vars[token] if meth_vars.key?(token) + + # Else get out of here + meth_vars[token] = "#{@method_name}_#{meth_vars.length}" + end + end +end diff --git a/lib/normalizers/method_internal_naming_normalising.rb b/lib/normalizers/method_internal_naming_normalising.rb new file mode 100644 index 0000000..ebb46d9 --- /dev/null +++ b/lib/normalizers/method_internal_naming_normalising.rb @@ -0,0 +1,114 @@ +require 'parser/current' + +# class Normalize < Parser::AST::Processor +class NamingNormalizers::MethodInternals < Parser::TreeRewriter + include Mandate + + def initialize(code, mapping) + @original_code = code + @mapping = mapping + end + + def call + buffer = Parser::Source::Buffer.new('', source: original_code) + builder = RuboCop::AST::Builder.new + ast = Parser::CurrentRuby.new(builder).parse(buffer) + rewrite(buffer, ast) + end + + %i[ + on_argument + on_const + on_var + on_vasgn + ].each do |method_name| + define_method method_name do |node| + replace_loc_name(node) + super(node) + end + end + + def on_def(node) + # node.pry + p node.loc.name.source + # @method_scope = metho + replace_loc_name(node) + super(node) + end + + def on_send(node) + # node.pry + if !node.enumerator_method? && + !node.operator_method? + replace_loc_selector(node) + end + + super + end + + def process_regular_node + p "HERE?" + super + end + + def on_op_asgn(node) + # p "opasgn" + #node.pry + super + end + + def on_casgn(node) + # p "casgn" + #node.pry + super + end + + def on_defs(node) + # p "defs" + #node.pry + super + end + + def on_numblock(node) + # p "numblock" + #node.pry + super + end + + def handler_missing(node) + case node.type + # noop + when true, :str, :nil, :int + super + else + p "handler_missing" + #node.pry + end + end + + private + attr_reader :original_code, :mapping + + def replace_loc_name(node) + p node.type + placeholder = case node.type + when :def + # node.pry + placeholder_for(:method, node.loc.name.source) + else + placeholder_for(:misc, node.loc.name.source) + end + + replace(node.loc.name, placeholder) + end + + def replace_loc_selector(node) + replace(node.loc.selector, placeholder_for(node.loc.selector.source)) + end + + def placeholder_for(type, token) + key = "#{type}_#{token}" + mapping.key?(key) ? mapping[key] : key + end +end + diff --git a/lib/normalizers/naming_normalizer.rb b/lib/normalizers/naming_normalizer.rb index dfc41b7..c130c79 100644 --- a/lib/normalizers/naming_normalizer.rb +++ b/lib/normalizers/naming_normalizer.rb @@ -19,7 +19,6 @@ def call %i[ on_argument on_const - on_def on_var on_vasgn ].each do |method_name| @@ -29,6 +28,14 @@ def call end end + def on_def(node) + # node.pry + p node.loc.name.source + # @method_scope = metho + replace_loc_name(node) + super(node) + end + def on_send(node) # node.pry if !node.enumerator_method? && @@ -44,25 +51,25 @@ def process_regular_node end def on_op_asgn(node) - p "opasgn" + # p "opasgn" #node.pry super end def on_casgn(node) - p "casgn" + # p "casgn" #node.pry super end def on_defs(node) - p "defs" + # p "defs" #node.pry super end def on_numblock(node) - p "numblock" + # p "numblock" #node.pry super end @@ -82,14 +89,24 @@ def handler_missing(node) attr_reader :original_code, :mapping def replace_loc_name(node) - replace(node.loc.name, placeholder_for(node.loc.name.source)) + p node.type + placeholder = case node.type + when :def + # node.pry + placeholder_for(:method, node.loc.name.source) + else + placeholder_for(:misc, node.loc.name.source) + end + + replace(node.loc.name, placeholder) end def replace_loc_selector(node) replace(node.loc.selector, placeholder_for(node.loc.selector.source)) end - def placeholder_for(token) - mapping.key?(token) ? mapping[token] : token + def placeholder_for(type, token) + key = "#{type}_#{token}" + mapping.key?(key) ? mapping[key] : key end end diff --git a/lib/representer.rb b/lib/representer.rb index a8f299a..c143d7d 100644 --- a/lib/representer.rb +++ b/lib/representer.rb @@ -4,6 +4,8 @@ require 'parser/current' require 'pathname' +require_relative 'naming_normalizers/base' +require_relative 'naming_normalizers/method_locals' require_relative 'normalizers/naming_normalizer' require_relative 'generate_mapping' @@ -11,7 +13,7 @@ require_relative 'representation' require_relative 'represent_solution' -#require 'pry' +require 'pry' module Representer def self.generate(exercise_slug, solution_path, output_path) diff --git a/test/naming_normalizers/method_locals.rb b/test/naming_normalizers/method_locals.rb new file mode 100644 index 0000000..2b4f708 --- /dev/null +++ b/test/naming_normalizers/method_locals.rb @@ -0,0 +1,176 @@ +require "test_helper" + +class NamingNormalizers::MethodLocalsTest < Minitest::Test + def test_variable_name_outside_of_method + assert_noop("foobar = true") + end + + def test_local_variable + assert_rewritten( + "def foo + foobar = true + foobar = false + barfoo = 1 + end", + + "def foo + foo_0 = true + foo_0 = false + foo_1 = 1 + end" + ) + end + + def test_local_variable_being_used + assert_rewritten( + "def foo + foobar = true + puts(foobar) + end", + + "def foo + foo_0 = true + puts(foo_0) + end" + ) + end + + def test_two_methods + assert_rewritten( + "def foo + foobar = true + puts(foobar) + end + + def bar + foobar = true + puts(foobar) + end", + + "def foo + foo_0 = true + puts(foo_0) + end + + def bar + bar_0 = true + puts(bar_0) + end" + ) + end + + def test_arg + assert_rewritten( + "def foo(foobar) + foobar = true + puts(foobar) + end", + + "def foo(foo_0) + foo_0 = true + puts(foo_0) + end" + ) + end + + + + +# def test_class_name +# code = "class Foobar; end" +# representation = "class Foobar; end" +# assert_rewritten code, representation +# end + +# def test_method_name +# code = "def foobar; end" +# representation = "def foobar; end" +# assert_rewritten code, representation +# end + +# def test_if +# code = "foo = true; if foo then 'bar' else nil end" +# representation = "placeholder_0 = true; if placeholder_0 then 'bar' else nil end" +# assert_rewritten code, representation +# end + +# def test_return +# code = "foo = true; return foo" +# representation = "placeholder_0 = true; return placeholder_0" +# assert_rewritten code, representation +# end + +# def test_method_call +# code = ' +# def bar; end +# foo.bar +# ' +# representation = ' +# def placeholder_0; end +# foo.placeholder_0 +# ' +# assert_rewritten code, representation +# end + +# def test_non_defined_method_call +# code = "foo = []; foo.each" +# representation = "placeholder_0 = []; placeholder_0.each" +# assert_rewritten code, representation +# end + +# def test_args +# code = %{ +# foo = 1 +# bar = 2 +# def somefunc(param1, bar) +# return param1 + bar +# end +# } +# representation = %{ +# placeholder_0 = 1 +# placeholder_1 = 2 +# def placeholder_2(placeholder_3, placeholder_1) +# return placeholder_3 + placeholder_1 +# end +# } +# assert_rewritten code, representation +# end + +# def test_complex_example +# code = ' +# class TwoFer +# def two_fer +# "foo" +# end + +# def foobar +# two_fer = "cat" +# return TwoFer.two_fer +# end +# end +# ' +# representation = ' +# class PLACEHOLDER_0 +# def placeholder_1 +# "foo" +# end + +# def placeholder_2 +# placeholder_1 = "cat" +# return PLACEHOLDER_0.placeholder_1 +# end +# end +# ' +# assert_rewritten(code, representation) +# end + + def assert_noop(code) + assert_rewritten(code, code) + end + + def assert_rewritten(code, expected) + actual = NamingNormalizers::MethodLocals.(code) + assert_equal expected.strip, actual.strip + end +end + diff --git a/test/sanity_test.rb b/test/sanity_test.rb new file mode 100644 index 0000000..6936955 --- /dev/null +++ b/test/sanity_test.rb @@ -0,0 +1,100 @@ +require "test_helper" + +# The purpose of these tests it to ensure that things +# can actually work in reality rather than just in theory, +# that feedback can be sensibly given. It is a sanity check +# for the whole process of representing as much as just this +# Ruby representer. + +class SanityTest < Minitest::Test + def test_1 + code_1 = <<-CODE + def add_2(a) + a + 2 + end + + def add_3(a) + a + 3 + end + CODE + + code_2 = <<-CODE + def add_2(a) + a + 2 + end + + def add_3(b) + b + 3 + end + CODE + + code_3 = <<-CODE + def add_2(b) + b + 2 + end + + def add_3(b) + b + 3 + end + CODE + + representation_1 = Representation.new(code_1) + representation_1.normalize! + + representation_2 = Representation.new(code_2) + representation_2.normalize! + + representation_3 = Representation.new(code_3) + representation_3.normalize! + + assert_equal representation_1.ast, representation_2.ast + assert_equal representation_1.ast, representation_3.ast + end +end + +# def test_1 +# code_1 = <<-CODE +# foobar = "This is nice" + +# def add_2(a) +# a + 2 +# end + +# def add_3(a) +# a + 3 +# end + +# class TwoFer +# def two_fer +# "foo" +# end + +# def foobar +# two_fer = "cat" +# return TwoFer.two_fer +# end +# end +# CODE + +# code_2 = <<-CODE +# something = "This is nice" + +# class TwoFer +# def two_fer +# "foo" +# end + +# def foobar +# mouse = "cat" +# return TwoFer.two_fer +# end +# end +# CODE + +# representation = Representation.new(code) +# representation.normalize! + +# # Let's give feedback on the first + +# """ +# """