diff --git a/lib/generator.rb b/lib/generator.rb index ada326d026..d14497448f 100644 --- a/lib/generator.rb +++ b/lib/generator.rb @@ -15,7 +15,7 @@ def initialize(track:, metadata:) # Doesn't update the version information. class GenerateTests < ImplementationDelegator def call - create_tests_file + build_tests end end @@ -24,7 +24,7 @@ class UpdateVersionAndGenerateTests < ImplementationDelegator def call update_tests_version update_example_solution - create_tests_file + build_tests end end end diff --git a/lib/generator/command_line.rb b/lib/generator/command_line.rb index aff48ba98b..91bd9cac7d 100644 --- a/lib/generator/command_line.rb +++ b/lib/generator/command_line.rb @@ -16,7 +16,7 @@ def parse(args) attr_reader :paths def generators - implementations.map { |slug| generator(implementation(slug)) } + implementations.map { |slug| generator(implementation(exercise(slug))) } end def implementations @@ -35,9 +35,13 @@ def freeze? @options[:freeze] || @options[:all] end - def implementation(slug) + def exercise(slug) + Exercise.new(slug: slug) + end + + def implementation(exercise) LoggingImplementation.new( - implementation: Implementation.new(paths: paths, slug: slug), + implementation: Implementation.new(paths: paths, exercise: exercise), logger: logger ) end diff --git a/lib/generator/exercise.rb b/lib/generator/exercise.rb new file mode 100644 index 0000000000..e858a12d1e --- /dev/null +++ b/lib/generator/exercise.rb @@ -0,0 +1,19 @@ +module Generator + class Exercise + using Generator::Underscore + + attr_reader :slug + + def initialize(slug:) + @slug = slug + end + + def name + @name ||= slug.underscore + end + + def case_class + slug.camel_case + 'Case' + end + end +end diff --git a/lib/generator/files/generator_cases.rb b/lib/generator/files/generator_cases.rb index b60d737a2a..562bc0da37 100644 --- a/lib/generator/files/generator_cases.rb +++ b/lib/generator/files/generator_cases.rb @@ -6,10 +6,6 @@ def available(track_path) cases_filepaths(track_path).map { |filepath| slugify(filepath) }.sort end - def class_name(exercise_name_or_slug) - filename(exercise_name_or_slug).split('_').map(&:capitalize).join - end - def source_filepath(track_path, slug) path = meta_generator_path(track_path, slug) filename = filename(slug) + '.rb' diff --git a/lib/generator/files/metadata_files.rb b/lib/generator/files/metadata_files.rb index 995b27a415..75e9db7f84 100644 --- a/lib/generator/files/metadata_files.rb +++ b/lib/generator/files/metadata_files.rb @@ -10,7 +10,7 @@ def canonical_data private def exercise_metadata_path - File.join(paths.metadata, 'exercises', slug) + File.join(paths.metadata, 'exercises', exercise.slug) end end diff --git a/lib/generator/files/track_files.rb b/lib/generator/files/track_files.rb index e7871b8cc4..9642ecceb2 100644 --- a/lib/generator/files/track_files.rb +++ b/lib/generator/files/track_files.rb @@ -22,7 +22,7 @@ def tests_template private def exercise_path - File.join(paths.track, 'exercises', slug) + File.join(paths.track, 'exercises', exercise.slug) end def meta_path @@ -34,7 +34,7 @@ def solutions_path end def minitest_tests_filename - "#{exercise_name}_test.rb" + "#{exercise.name}_test.rb" end def version_filename @@ -42,7 +42,7 @@ def version_filename end def example_filename - "#{exercise_name}.rb" + "#{exercise.name}.rb" end def tests_template_absolute_filename diff --git a/lib/generator/implementation.rb b/lib/generator/implementation.rb index e94e62c80f..b939d3703f 100644 --- a/lib/generator/implementation.rb +++ b/lib/generator/implementation.rb @@ -6,12 +6,12 @@ class Implementation include Files::MetadataFiles include TemplateValuesFactory - def initialize(paths:, slug:) + def initialize(paths:, exercise:) @paths = paths - @slug = slug + @exercise = exercise end - attr_reader :paths, :slug + attr_reader :paths, :exercise def version tests_version.to_i @@ -25,16 +25,12 @@ def update_example_solution example_solution.update_version(version) end - def create_tests_file + def build_tests minitest_tests.generate( template: tests_template.to_s, values: template_values ) end - - def exercise_name - @exercise_name ||= slug.tr('-', '_') - end end # This exists to give us a clue as to what we are delegating to. @@ -58,9 +54,9 @@ def update_example_solution @logger.debug "Updated version in example solution to #{version}" end - def create_tests_file - @implementation.create_tests_file - @logger.info "Generated #{slug} tests version #{version}" + def build_tests + @implementation.build_tests + @logger.info "Generated #{exercise.slug} tests version #{version}" end end end diff --git a/lib/generator/template_values.rb b/lib/generator/template_values.rb index 3f80238daa..61f78e0af5 100644 --- a/lib/generator/template_values.rb +++ b/lib/generator/template_values.rb @@ -28,30 +28,26 @@ def template_values abbreviated_commit_hash: canonical_data.abbreviated_commit_hash, canonical_data_version: canonical_data.version, version: version, - exercise_name: slug_underscore, + exercise_name: exercise.name, test_cases: extract ) end private - def slug_underscore - slug ? slug.tr('-_', '_') : '' - end - def extract load cases_load_name extractor.cases(canonical_data.to_s) end def extractor - CaseValues::Extractor.new( - case_class: Object.const_get(Files::GeneratorCases.class_name(slug)) - ) + CaseValues::Extractor.new( + case_class: Object.const_get(exercise.case_class) + ) end def cases_load_name - Files::GeneratorCases.source_filepath(paths.track, slug) + Files::GeneratorCases.source_filepath(paths.track, exercise.slug) end end end diff --git a/lib/generator/underscore.rb b/lib/generator/underscore.rb index 79727ffff7..5cd56745e2 100644 --- a/lib/generator/underscore.rb +++ b/lib/generator/underscore.rb @@ -4,6 +4,10 @@ module Underscore def underscore downcase.gsub(/[- ]/, '_').gsub(/[^\w?]/, '') end + + def camel_case + underscore.split('_').map(&:capitalize).join + end end refine Fixnum do diff --git a/test/fixtures/xruby/lib/generator/test_template.erb b/test/fixtures/xruby/lib/generator/test_template.erb index 0e90df5d8b..1beb65b1f1 100644 --- a/test/fixtures/xruby/lib/generator/test_template.erb +++ b/test/fixtures/xruby/lib/generator/test_template.erb @@ -1,9 +1,9 @@ #!/usr/bin/env ruby require 'minitest/autorun' -require_relative 'acronym' +require_relative '<%= exercise_name %>' -# Common test data version: <%= abbreviated_commit_hash %> -class AcronymTest < Minitest::Test +# Common test data version: <%= canonical_data_version %> <%= abbreviated_commit_hash %> +class <%= exercise_name_camel %>Test < Minitest::Test <% test_cases.each_with_index do |test_case, idx| %> def <%= test_case.name %> <%= test_case.skipped(idx) %> diff --git a/test/generator/exercise_test.rb b/test/generator/exercise_test.rb new file mode 100644 index 0000000000..37ad555991 --- /dev/null +++ b/test/generator/exercise_test.rb @@ -0,0 +1,20 @@ +require_relative '../test_helper' + +module Generator + class ExerciseTest < Minitest::Test + def test_slug + exercise = Exercise.new(slug: 'alpha') + assert_equal 'alpha', exercise.slug + end + + def test_name + exercise = Exercise.new(slug: 'alpha-beta') + assert_equal 'alpha_beta', exercise.name + end + + def test_case_class + exercise = Exercise.new(slug: 'alpha-beta') + assert_equal 'AlphaBetaCase', exercise.case_class + end + end +end diff --git a/test/generator/files/generate_cases_test.rb b/test/generator/files/generate_cases_test.rb index ae5882673c..1baf46996c 100644 --- a/test/generator/files/generate_cases_test.rb +++ b/test/generator/files/generate_cases_test.rb @@ -22,10 +22,6 @@ def test_available_calls_glob_with_the_right_arguments mock_glob_call.verify end - def test_class_name - assert_equal 'TwoParterCase', GeneratorCases.class_name('two-parter') - end - def test_source_filepath track_path = '/track' slug = 'slug' diff --git a/test/generator/files/metadata_files_test.rb b/test/generator/files/metadata_files_test.rb index 82e3682f8c..3c3e205fa8 100644 --- a/test/generator/files/metadata_files_test.rb +++ b/test/generator/files/metadata_files_test.rb @@ -10,9 +10,9 @@ class MetadataFilesTest < Minitest::Test class TestMetadataFiles def initialize @paths = FixturePaths - @slug = 'alpha' + @exercise = Exercise.new(slug: 'alpha') end - attr_reader :paths, :slug + attr_reader :paths, :exercise include MetadataFiles end diff --git a/test/generator/files/track_files_test.rb b/test/generator/files/track_files_test.rb index 53c97e1de7..6854b77cec 100644 --- a/test/generator/files/track_files_test.rb +++ b/test/generator/files/track_files_test.rb @@ -11,10 +11,9 @@ class TrackFilesTest < Minitest::Test class TestTrackFiles def initialize @paths = FixturePaths - @slug = 'alpha-beta' - @exercise_name = 'alpha_beta' + @exercise = Exercise.new(slug: 'alpha-beta') end - attr_accessor :paths, :slug, :exercise_name + attr_reader :paths, :exercise include TrackFiles end @@ -44,9 +43,9 @@ def test_tests_template class TestTrackFilesUseDefault def initialize @paths = FixturePaths - @slug = 'notemplate' + @exercise = Exercise.new(slug: 'notemplate') end - attr_reader :paths, :slug + attr_reader :paths, :exercise include TrackFiles end diff --git a/test/generator/implementation_test.rb b/test/generator/implementation_test.rb index 828db9615d..c8a907ca9f 100644 --- a/test/generator/implementation_test.rb +++ b/test/generator/implementation_test.rb @@ -8,18 +8,14 @@ class ImplementationTest < Minitest::Test ) def test_version - subject = Implementation.new(paths: FixturePaths, slug: 'alpha') + exercise = Minitest::Mock.new.expect :slug, 'alpha' + subject = Implementation.new(paths: FixturePaths, exercise: exercise) assert_equal 1, subject.version end - def test_slug - subject = Implementation.new(paths: FixturePaths, slug: 'alpha') - assert_equal 'alpha', subject.slug - end - def test_update_tests_version mock_file = Minitest::Mock.new.expect :write, '2'.length, [2] - subject = Implementation.new(paths: FixturePaths, slug: 'alpha') + subject = Implementation.new(paths: FixturePaths, exercise: Exercise.new(slug: 'alpha')) # Verify iniital condition from fixture file assert_equal 1, subject.tests_version.to_i File.stub(:open, true, mock_file) do @@ -31,14 +27,14 @@ def test_update_tests_version def test_update_example_solution expected_content = "# This is the example\n\nclass BookKeeping\n VERSION = 1\nend\n" mock_file = Minitest::Mock.new.expect :write, expected_content.length, [expected_content] - subject = Implementation.new(paths: FixturePaths, slug: 'alpha') + subject = Implementation.new(paths: FixturePaths, exercise: Exercise.new(slug: 'alpha')) File.stub(:open, true, mock_file) do assert_equal expected_content, subject.update_example_solution end mock_file.verify end - def test_create_tests_file + def test_build_tests # Q: Is the pain here caused by: # a) Implementation `including` everything rather than using composition? # b) Trying to verify the expected content. @@ -84,34 +80,30 @@ def test_bookkeeping end TESTS_FILE mock_file = Minitest::Mock.new.expect :write, expected_content.length, [expected_content] - subject = Implementation.new(paths: FixturePaths, slug: 'alpha') + subject = Implementation.new(paths: FixturePaths, exercise: Exercise.new(slug: 'alpha')) GitCommand.stub(:abbreviated_commit_hash, '123456789') do File.stub(:open, true, mock_file) do - assert_equal expected_content, subject.create_tests_file + assert_equal expected_content, subject.build_tests end end mock_file.verify # Don't pollute the namespace Object.send(:remove_const, :AlphaCase) end - - def test_exercise_name - subject = Implementation.new(paths: FixturePaths, slug: 'alpha-beta') - assert_equal 'alpha_beta', subject.exercise_name - end end class LoggingImplementationTest < Minitest::Test - def test_create_tests_file + def test_build_tests + exercise = Exercise.new(slug: 'alpha') mock_implementation = Minitest::Mock.new - mock_implementation.expect :create_tests_file, nil - mock_implementation.expect :slug, 'alpha' + mock_implementation.expect :build_tests, nil + mock_implementation.expect :exercise, exercise mock_implementation.expect :version, 2 mock_logger = Minitest::Mock.new mock_logger.expect :info, nil, ['Generated alpha tests version 2'] subject = LoggingImplementation.new(implementation: mock_implementation, logger: mock_logger) - subject.create_tests_file + subject.build_tests mock_implementation.verify end diff --git a/test/generator/template_values_test.rb b/test/generator/template_values_test.rb index ee179cc28b..d2b289d9a4 100644 --- a/test/generator/template_values_test.rb +++ b/test/generator/template_values_test.rb @@ -46,8 +46,8 @@ def test_get_binding class TemplateValuesFactoryTest < Minitest::Test class TestTemplateValuesFactory - def slug - 'alpha' + def exercise + Exercise.new(slug: 'alpha') end def version @@ -71,37 +71,6 @@ def paths include TemplateValuesFactory end - class ClassBasedTestTemplateValuesFactory - def slug - 'beta' - end - - def version - 2 - end - - def canonical_data - mock_canonical_data = Minitest::Mock.new - mock_canonical_data.expect :abbreviated_commit_hash, nil - mock_canonical_data.expect :version, '1.2.3' - mock_canonical_data.expect :to_s, '{"cases":[]}' - mock_canonical_data - end - - def paths - mock_paths = Minitest::Mock.new - mock_paths.expect :track, 'test/fixtures/xruby' - mock_paths - end - - include TemplateValuesFactory - end - - def test_template_values_from_class - subject = ClassBasedTestTemplateValuesFactory.new - assert_instance_of TemplateValues, subject.template_values - end - def test_template_values_loads_problem_case_classes subject = TestTemplateValuesFactory.new assert_instance_of TemplateValues, subject.template_values diff --git a/test/generator/underscore_test.rb b/test/generator/underscore_test.rb index c0345772e7..50cf6cf036 100644 --- a/test/generator/underscore_test.rb +++ b/test/generator/underscore_test.rb @@ -20,6 +20,10 @@ def test_question_mark ) end + def test_camel_case + assert_equal 'ASlug', 'a-slug'.camel_case + end + def test_fixnum_underscore assert_equal '1_000_000', 1000000.underscore end diff --git a/test/generator_test.rb b/test/generator_test.rb index 2959a4cb87..b376960afa 100644 --- a/test/generator_test.rb +++ b/test/generator_test.rb @@ -6,7 +6,7 @@ def test_call mock_exercise = Minitest::Mock.new mock_exercise.expect :update_tests_version, nil mock_exercise.expect :update_example_solution, nil - mock_exercise.expect :create_tests_file, nil + mock_exercise.expect :build_tests, nil subject = UpdateVersionAndGenerateTests.new(mock_exercise) subject.call @@ -18,7 +18,7 @@ def test_call class UpdateVersionAndGenerateTestsFrozenVersionTest < Minitest::Test def test_call mock_exercise = Minitest::Mock.new - mock_exercise.expect :create_tests_file, nil + mock_exercise.expect :build_tests, nil subject = GenerateTests.new(mock_exercise) subject.call