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

Method for fetching local or remote metadata files #81

Merged
merged 18 commits into from
Jul 10, 2017
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
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@
!bin/fetch-configlet
!LICENSE
!Makefile
!generator/

# make sure to ignore others
# double ignore others
*.swp
.crystal/
.DS_Store
bin/configlet
bin/configlet.exe
CHECKLIST
tmp/
bin/generate
bin/generator
cache/
generator/lib
generator/.shards
generator/bin/generator
37 changes: 27 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,34 +1,51 @@
EXERCISE ?= ""
IGNOREDIRS := "^(\.git|.crystal|docs|bin|img|script)$$"
EXERCISESDIR ?= "exercises"
GENERATORDIR ?= "src/generator"
EXERCISES = $(shell find exercises -maxdepth 1 -mindepth 1 -type d | cut -d'/' -f2 | sort | grep -Ev $(IGNOREDIRS))

FILEEXT = "cr"
SPECDIR = "spec"
EXERCISENAME := "$(subst -,_,$(EXERCISE))"
EXERCISEDIR := $(EXERCISESDIR)/$(EXERCISE)
EXERCISESPECDIR := $(EXERCISEDIR)/$(SPECDIR)
EXERCISESPECDIR := $(EXERCISESDIR)/$(EXERCISE)/$(SPECDIR)
SPECFILE := "$(EXERCISENAME)_spec.$(FILEEXT)"
SUPERTMPSPECFILE := "$(SPECFILE).super.tmp"
SUPERSPECFILE := "$(SPECFILE).super"
TMPSPECFILE := "$(SPECFILE).tmp"

GENERATORDIR ?= "generator"
GENERATORSDIR := $(GENERATORDIR)/src/generators
GENERATORS = $(shell find $(GENERATORSDIR) -type f | cut -d '/' -f 4 | cut -d '.' -f 1 | sed 's/_/-/g')

test-exercise:
@echo "running formatting check for: $(EXERCISE)"
@crystal tool format --check $(EXERCISESDIR)/$(EXERCISE)
@echo "moving files around"
@sed 's/pending/it/g' $(EXERCISESPECDIR)/$(SPECFILE) > $(EXERCISESPECDIR)/$(TMPSPECFILE)
@mv $(EXERCISESPECDIR)/$(SPECFILE) $(EXERCISESPECDIR)/$(SUPERTMPSPECFILE)
@mv $(EXERCISESPECDIR)/$(SPECFILE) $(EXERCISESPECDIR)/$(SUPERSPECFILE)
@mv $(EXERCISESPECDIR)/$(TMPSPECFILE) $(EXERCISESPECDIR)/$(SPECFILE)
@echo "running tests for: $(EXERCISE)"
@cd $(EXERCISESDIR)/$(EXERCISE) && crystal spec
@rm $(EXERCISESPECDIR)/$(SPECFILE)
@mv $(EXERCISESPECDIR)/$(SUPERTMPSPECFILE) $(EXERCISESPECDIR)/$(SPECFILE)
@mv $(EXERCISESPECDIR)/$(SUPERSPECFILE) $(EXERCISESPECDIR)/$(SPECFILE)
@printf "\n"

test:
test-exercises:
@for exercise in $(EXERCISES); do EXERCISE=$$exercise $(MAKE) -s test-exercise || exit 1; done

build-generator:
@crystal build $(GENERATORDIR)/generator.$(FILEEXT) -o generator/bin/generator

generate-exercise:
@echo "generating spec file for generator: $(GENERATOR)"
@generator/bin/generator $(GENERATOR)

generate-exercises:
@for generator in $(GENERATORS); do GENERATOR=$$generator $(MAKE) -s generate-exercise || exit 1; done

test-generator:
@echo "running generator tests"
@cd $(GENERATORDIR) && crystal spec
@cd $(GENERATORDIR) && crystal deps && crystal spec

build_generator:
@crystal build $(GENERATORDIR)/generate.$(FILEEXT) -o bin/generate
test:
@echo "running all the tests"
@$(MAKE) -s test-exercises
@$(MAKE) -s test-generator
7 changes: 7 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@
"difficulty": 3,
"topics": [

]
},
{
"slug": "flatten-array",
"difficulty": 1,
"topics": [

]
}
],
Expand Down
28 changes: 28 additions & 0 deletions exercises/flatten-array/spec/flatten_array_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require "spec"
require "../src/*"

describe "FlattenArray" do
it "no nesting" do
FlattenArray.flatten([0, 1, 2]).should eq([0, 1, 2])
end

pending "flattens array with just integers present" do
FlattenArray.flatten([1, [2, 3, 4, 5, 6, 7], 8]).should eq([1, 2, 3, 4, 5, 6, 7, 8])
end

pending "5 level nesting" do
FlattenArray.flatten([0, 2, [[2, 3], 8, 100, 4, [[[50]]]], -2]).should eq([0, 2, 2, 3, 8, 100, 4, 50, -2])
end

pending "6 level nesting" do
FlattenArray.flatten([1, [2, [[3]], [4, [[5]]], 6, 7], 8]).should eq([1, 2, 3, 4, 5, 6, 7, 8])
end

pending "6 level nest list with null values" do
FlattenArray.flatten([0, 2, [[2, 3], 8, [[100]], nil, [[nil]]], -2]).should eq([0, 2, 2, 3, 8, 100, -2])
end

pending "all values in nested list are null" do
FlattenArray.flatten([nil, [[[nil]]], nil, nil, [[nil, nil], nil], nil]).should eq([] of Nil)
end
end
7 changes: 7 additions & 0 deletions exercises/flatten-array/src/example.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module FlattenArray
extend self

def flatten(arr)
arr.flatten.compact
end
end
20 changes: 20 additions & 0 deletions generator/generator.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require "./src/exercise_generator"
require "./src/generators/*"

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

exercise = ARGV[0]

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

raise "Undefined Generator" unless klass
klass.generate
rescue ex
STDERR.puts ex.message
end
6 changes: 6 additions & 0 deletions generator/shard.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 1.0
shards:
webmock:
github: manastech/webmock.cr
commit: c673f393a31eac2734c7599897357ef1f3f24011

9 changes: 9 additions & 0 deletions generator/shard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: generator
version: 0.0.1

development_dependencies:
webmock:
github: manastech/webmock.cr
branch: master

license: MIT
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require "spec"
require "../exercises/exercise_generator"
require "../exercises/exercise_test_case"
require "../src/exercise_generator"
require "../src/exercise_test_case"

class DummyGenerator < ExerciseGenerator
def exercise_name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require "spec"
require "json"
require "../exercises/exercise_test_case"
require "../src/exercise_test_case"

class DummyTestCase < ExerciseTestCase
def workload; end
Expand Down
58 changes: 58 additions & 0 deletions generator/spec/remote_data_file_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
require "spec"
require "file_utils"
require "webmock"
require "../src/remote_data_file"

TEST_URL = [RemoteDataFile::BASE_URL, "test-exercise", RemoteDataFile::DATA_FILE].join("/")
TEST_DIR = File.expand_path(File.join("..", "..", "cache", "test-exercise"), __FILE__)

describe "RemoteDataFile" do
describe "#path" do
context "when successful" do
Spec.before_each do
clean_test_files
WebMock.reset
end

Spec.after_each do
clean_test_files
end

it "returns the response body if status is 200" do
WebMock.stub(:get, TEST_URL).to_return(status: 200, body: "file body")

remote_data_file = RemoteDataFile.new("test-exercise")

File.read(remote_data_file.path).should eq("file body")
end
end

context "when successful" do
it "raises a not found exception if status is 404" do
WebMock.stub(:get, TEST_URL).to_return(status: 404, body: "")

error_message = "A #{RemoteDataFile::DATA_FILE} doesn't exist for test-exercise in x-common. " +
"Go make one!"

expect_raises(Exception, error_message) do
RemoteDataFile.new("test-exercise").path
end
end

it "raises a unexpected exception if status is other than 200 or 404" do
WebMock.stub(:get, TEST_URL).to_return(status: 500, body: "")


error_message = "Error while requesting the test-exercise data file from GitHub... " +
"Status was 500"
expect_raises(Exception, error_message) do
RemoteDataFile.new("test-exercise").path
end
end
end
end
end

def clean_test_files
FileUtils.rm_rf(TEST_DIR)
end
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "./remote_data_file"

require "ecr"
require "json"

Expand All @@ -21,7 +23,7 @@ abstract class ExerciseGenerator
abstract def test_cases

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

private def test_file
Expand All @@ -33,7 +35,13 @@ abstract class ExerciseGenerator
end

private def data
File.read(File.join(metadata_dir, "canonical-data.json"))
local_data_file = File.join(metadata_dir, "canonical-data.json")
if File.exists?(local_data_file)
File.read(local_data_file)
else
remote_data_file = RemoteDataFile.new(exercise_name)
File.read(remote_data_file.path)
end
end

ECR.def_to_s "#{__DIR__}/templates/example.tt"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "./exercise_generator"
require "./exercise_test_case"
require "../exercise_generator"
require "../exercise_test_case"

class AcronymGenerator < ExerciseGenerator
def exercise_name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "./exercise_generator"
require "./exercise_test_case"
require "../exercise_generator"
require "../exercise_test_case"

class BinaryGenerator < ExerciseGenerator
def exercise_name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "./exercise_generator"
require "./exercise_test_case"
require "../exercise_generator"
require "../exercise_test_case"

class DifferenceOfSquaresGenerator < ExerciseGenerator
def exercise_name
Expand Down
43 changes: 43 additions & 0 deletions generator/src/generators/flatten_array.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
require "../exercise_generator"
require "../exercise_test_case"

class FlattenArrayGenerator < ExerciseGenerator
def exercise_name
"flatten-array"
end

def test_cases
JSON.parse(data)["cases"].map do |test_case|
FlattenArrayTestCase.new(test_case)
end
end
end

class FlattenArrayTestCase < ExerciseTestCase
private getter description : JSON::Any
private getter input : JSON::Any
private getter expected : JSON::Any

def initialize(test_case)
@description = test_case["description"]
@input = test_case["input"]
@expected = fix_empty_array(test_case["expected"])
end

def workload
"FlattenArray.flatten(#{input}).should eq(#{expected})"
end

def test_name
description
end

def fix_empty_array(input)
if input.to_s.match(/\[\]/)
json = "[] of Nil".to_json
JSON.parse(json)
else
input
end
end
end
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "./exercise_generator"
require "./exercise_test_case"
require "../exercise_generator"
require "../exercise_test_case"

class ForthGenerator < ExerciseGenerator
def exercise_name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "./exercise_generator"
require "./exercise_test_case"
require "../exercise_generator"
require "../exercise_test_case"

class HelloWorldGenerator < ExerciseGenerator
def exercise_name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "./exercise_generator"
require "./exercise_test_case"
require "../exercise_generator"
require "../exercise_test_case"

class PascalsTriangleGenerator < ExerciseGenerator
def exercise_name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "./exercise_generator"
require "./exercise_test_case"
require "../exercise_generator"
require "../exercise_test_case"

class RunLengthEncodingGenerator < ExerciseGenerator
def exercise_name
Expand Down
Loading