Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exercise generator #52

Merged
merged 3 commits into from
Nov 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ bin/configlet
bin/configlet.exe
CHECKLIST
tmp/
bin/generate
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ASSIGNMENT ?= ""
IGNOREDIRS := "^(\.git|.crystal|docs|bin|img|script)$$"
EXERCISESDIR ?= "exercises"
GENERATORDIR ?= "src/generator"
ASSIGNMENTS = $(shell find exercises -maxdepth 1 -mindepth 1 -type d | cut -d'/' -f2 | sort | grep -Ev $(IGNOREDIRS))

FILEEXT := "cr"
Expand All @@ -23,3 +24,8 @@ test-assignment:

test:
@for assignment in $(ASSIGNMENTS); do ASSIGNMENT=$$assignment $(MAKE) -s test-assignment || exit 1; done
@echo "running generator tests"
@cd $(GENERATORDIR) && crystal spec

build_generator:
@crystal build $(GENERATORDIR)/generate.$(FILEEXT) -o bin/generate
3 changes: 2 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@
"ignored": [
"bin",
"docs",
"img"
"img",
"src"
],
"foregone": [
]
Expand Down
18 changes: 8 additions & 10 deletions exercises/hello-world/spec/hello_world_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ require "spec"
require "../src/*"

describe "HelloWorld" do
describe "#hello" do
it "says hello with default 'World'" do
HelloWorld.hello.should eq "Hello, World!"
end
it "tests no name" do
HelloWorld.hello.should eq("Hello, World!")
end

pending "says hello with one name" do
HelloWorld.hello("Max").should eq "Hello, Max!"
end
pending "tests sample name" do
HelloWorld.hello("Alice").should eq("Hello, Alice!")
end

pending "says hello with another name" do
HelloWorld.hello("Alice").should eq "Hello, Alice!"
end
pending "tests other sample name" do
HelloWorld.hello("Bob").should eq("Hello, Bob!")
end
end
39 changes: 39 additions & 0 deletions src/generator/exercises/exercise_generator.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require "ecr"
require "json"

abstract class ExerciseGenerator
METADATA_REPOSITORY = "x-common"

def self.generate
new.generate
end

def generate
File.write(test_file, to_s)
end

def describe_name
exercise_name.split('-').map(&.capitalize).join
end

abstract def exercise_name : String
abstract def test_cases : Array(ExerciseTestCase)

private def root
File.expand_path(File.join("..", "..", "..", ".."), __FILE__)
end

private def test_file
File.expand_path(File.join("exercises", exercise_name, "spec", "#{exercise_name.tr("-", "_")}_spec.cr"), root)
end

private def metadata_dir
File.expand_path(File.join("..", METADATA_REPOSITORY, "exercises", exercise_name), root)
end

private def data
File.read(File.join(metadata_dir, "canonical-data.json"))
end

ECR.def_to_s "#{__DIR__}/templates/example.tt"
end
8 changes: 8 additions & 0 deletions src/generator/exercises/exercise_test_case.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
abstract class ExerciseTestCase
abstract def workload
abstract def test_name

def pending?(index)
index == 0 ? "it" : "pending"
end
end
34 changes: 34 additions & 0 deletions src/generator/exercises/hello_world.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require "./exercise_generator"
require "./exercise_test_case"

class HelloWorldGenerator < ExerciseGenerator
def exercise_name
"hello-world"
end

def test_cases
JSON.parse(data)["cases"].map do |test_case|
HelloWorldTestCase.from_json(test_case.to_json)
end
end
end

class HelloWorldTestCase < ExerciseTestCase
JSON.mapping(
description: String,
name: String | Nil,
expected: String
)

def workload
if name
"HelloWorld.hello(\"#{name}\").should eq(\"#{expected}\")"
else
"HelloWorld.hello.should eq(\"#{expected}\")"
end
end

def test_name
description
end
end
10 changes: 10 additions & 0 deletions src/generator/exercises/templates/example.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "spec"
require "../src/*"

describe <%= "#{describe_name.inspect} do" %>
<% test_cases.each_with_index do |test_case, index| %>
<%= test_case.pending?(index) %> "tests <%= test_case.test_name %>" do
<%= test_case.workload %>
end
<% end -%>
end
15 changes: 15 additions & 0 deletions src/generator/generate.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require "./exercises/*"

if ARGV.empty?
STDERR.puts "Exercise name required!\n"
exit
end

exercise = ARGV[0]

klass = {{ExerciseGenerator.subclasses}}.find do |generator|
generator.to_s == "#{exercise.split('-').map(&.capitalize).join}Generator"
end

raise "Undefined Generator" unless klass
klass.generate
27 changes: 27 additions & 0 deletions src/generator/spec/exercise_generator_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require "spec"
require "../exercises/exercise_generator"
require "../exercises/exercise_test_case"

class DummyGenerator < ExerciseGenerator
def exercise_name
"dummy"
end

def test_cases
[] of ExerciseTestCase
end
end

describe "ExerciseGenerator" do
describe "#describe_name" do
it "will return the name of the exercise in camel case" do
DummyGenerator.new.describe_name.should eq("Dummy")
end
end

describe "#to_s" do
it "will output the generator test file using the example.tt" do
DummyGenerator.new.to_s.should eq("require \"spec\"\nrequire \"../src/*\"\n\ndescribe \"Dummy\" do\nend\n")
end
end
end
27 changes: 27 additions & 0 deletions src/generator/spec/exercise_test_case_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require "spec"
require "json"
require "../exercises/exercise_test_case"

class DummyTestCase < ExerciseTestCase
JSON.mapping(
description: String
)

def workload; end

def test_name; end
end

describe "DummyTestCase" do
describe "#pending" do
it "outputs 'it' if the given integer is 0" do
dummy_test_case = DummyTestCase.from_json("{\"description\": \"hello\"}")
dummy_test_case.pending?(0).should eq("it")
end

it "outputs 'pending' if the given integer is greater than 0" do
dummy_test_case = DummyTestCase.from_json("{\"description\": \"hello\"}")
dummy_test_case.pending?(1).should eq("pending")
end
end
end