diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..163eb75 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*.cr] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0bbd4a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/docs/ +/lib/ +/bin/ +/.shards/ +*.dwarf + +# Libraries don't need dependency lock +# Dependencies will be locked in applications that use them +/shard.lock diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a485df8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Michael Wagner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..bdd56e7 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# lucky_template + +TODO: Write a description here + +## Installation + +1. Add the dependency to your `shard.yml`: + + ```yaml + dependencies: + lucky_template: + github: mdwagner/lucky_template + ``` + +2. Run `shards install` + +## Usage + +```crystal +require "lucky_template" +``` + +TODO: Write usage instructions here + +## Development + +TODO: Write development instructions here + +## Contributing + +1. Fork it () +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create a new Pull Request + +## Contributors + +- [Michael Wagner](https://github.com/mdwagner) - creator and maintainer diff --git a/shard.yml b/shard.yml new file mode 100644 index 0000000..1b54932 --- /dev/null +++ b/shard.yml @@ -0,0 +1,9 @@ +name: lucky_template +version: 0.1.0 + +authors: + - Michael Wagner + +crystal: ">= 1.0.0" + +license: MIT diff --git a/spec/lucky_template_spec.cr b/spec/lucky_template_spec.cr new file mode 100644 index 0000000..856126c --- /dev/null +++ b/spec/lucky_template_spec.cr @@ -0,0 +1,9 @@ +require "./spec_helper" + +describe LuckyTemplate do + # TODO: Write tests + + it "works" do + false.should eq(true) + end +end diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr new file mode 100644 index 0000000..7e10e6f --- /dev/null +++ b/spec/spec_helper.cr @@ -0,0 +1,2 @@ +require "spec" +require "../src/lucky_template" diff --git a/src/lucky_template.cr b/src/lucky_template.cr new file mode 100644 index 0000000..3648113 --- /dev/null +++ b/src/lucky_template.cr @@ -0,0 +1,103 @@ +require "file_utils" + +module LuckyTemplate + extend self + + VERSION = {{ `shards version #{__DIR__}`.chomp.stringify }} + + module LuckyTemplateable + abstract def to_lucky_template(io : IO) : Nil + end + + alias LuckyFileType = String | LuckyTemplateable | Nil + + class LuckyFile + getter name : String + + def initialize(@name, @file : LuckyFileType) + end + + def to_s(io : IO) : Nil + case @file + in LuckyTemplateable + @file.to_lucky_template(io) + in String, Nil + @file.to_s(io) + end + end + end + + class InvalidFolderName < Exception + def initialize(message = "Invalid folder name", cause : Exception? = nil) + super(message, cause: cause) + end + end + + class LuckyFolder + alias FileType = LuckyFile | LuckyFolder + getter name : String + getter files = [] of FileType + + # Writes folder to disk at path + def self.write!(location : Path, folder : LuckyFolder) : Nil + path = location.expand + FileUtils.mkdir_p(path) + folder.write_to_disk!(path) + end + + # Writes folder from path to disk at path dirname + def self.write!(location : Path, & : LuckyFolder ->) : Nil + path = location.expand + dirname = Path.new(path.dirname) + FileUtils.mkdir_p(dirname) + folder = LuckyFolder.new(path.basename) + yield folder + folder.write_to_disk!(dirname) + end + + def initialize(@name : String) + raise InvalidFolderName.new if @name.empty? + end + + def add_file(name : String, file : LuckyFileType) : Nil + add_file(LuckyFile.new(name, file)) + end + + def add_file(file : LuckyFile) : Nil + @files << file + end + + def add_folder(name : String) : Nil + add_folder(name) { } + end + + def add_folder(name : String, & : LuckyFolder ->) : Nil + folder = LuckyFolder.new(name) + yield folder + @files << folder + end + + protected def write_to_disk!(path : Path) : Nil + write_folder_to_disk!(path, self) + end + + private def write_file_to_disk!(path : Path, file : LuckyFile) : Nil + File.open(path.join(file.name), "w") do |io| + file.to_s(io) + end + end + + private def write_folder_to_disk!(path : Path, folder : LuckyFolder) : Nil + new_path = path.join(folder.name) + Dir.mkdir_p(new_path) + folder.files.each do |file| + case file + in LuckyFile + write_file_to_disk!(new_path, file) + in LuckyFolder + write_folder_to_disk!(new_path, file) + end + end + end + end +end