kojo 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +34 -14
- data/bin/kojo +1 -1
- data/lib/kojo.rb +1 -1
- data/lib/kojo/cli.rb +2 -0
- data/lib/kojo/collection.rb +38 -0
- data/lib/kojo/commands/config.rb +10 -4
- data/lib/kojo/commands/dir.rb +21 -20
- data/lib/kojo/commands/file.rb +8 -3
- data/lib/kojo/config.rb +66 -0
- data/lib/kojo/exceptions.rb +5 -0
- data/lib/kojo/extensions/array.rb +1 -0
- data/lib/kojo/extensions/string.rb +3 -2
- data/lib/kojo/template.rb +35 -12
- data/lib/kojo/version.rb +1 -1
- metadata +4 -2
- data/lib/kojo/generator.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60d550cda8b281a7ecbac40c236b6446fbe6a4d0b2ed7cb261ec47abeb654cbc
|
4
|
+
data.tar.gz: a991496e62aa272ad939b5c663cec543ed5e49aa9dedff5f3505c579d50de8d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa51aa1c425c7af70bd8fd12bed004c0472d290e96cfdb172e3222f76d994a671eba764b45baae57f1287ebb4f7ba27fa94f0fbf725edc714095740653c9507a
|
7
|
+
data.tar.gz: 58802308a1134db6abd3265b0f7ccacd854fe4cdef6468f6c15217799f75eaf03aae0e9761a2b990201ae6c50cb680f2bb026f1f8869be86930bbff4dce36779
|
data/README.md
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
![kojo](images/kojo.png)
|
4
4
|
|
5
|
-
Kojo
|
5
|
+
Kojo Configuration Ninja
|
6
6
|
==================================================
|
7
7
|
|
8
8
|
[![Gem Version](https://badge.fury.io/rb/kojo.svg)](https://badge.fury.io/rb/kojo)
|
9
9
|
[![Build Status](https://travis-ci.com/DannyBen/kojo.svg?branch=master)](https://travis-ci.com/DannyBen/kojo)
|
10
10
|
[![Maintainability](https://api.codeclimate.com/v1/badges/f24566ad04b5054a2251/maintainability)](https://codeclimate.com/github/DannyBen/kojo/maintainability)
|
11
|
-
|
11
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/f24566ad04b5054a2251/test_coverage)](https://codeclimate.com/github/DannyBen/kojo/test_coverage)
|
12
12
|
|
13
13
|
Kojo helps you generate configuration files from templates, using variables
|
14
14
|
and definition files.
|
@@ -25,8 +25,8 @@ Table of Contents
|
|
25
25
|
- [Usage](#usage)
|
26
26
|
- [Variables](#variables)
|
27
27
|
- [Import](#import)
|
28
|
-
- [One to Many Generation](#one-to-many-generation)
|
29
28
|
- [Compile an Entire Folder](#compile-an-entire-folder)
|
29
|
+
- [One to Many Generation](#one-to-many-generation)
|
30
30
|
- [Conditions and Loops with ERB](#conditions-and-loops-with-erb)
|
31
31
|
|
32
32
|
---
|
@@ -41,7 +41,7 @@ Installation
|
|
41
41
|
Usage
|
42
42
|
--------------------------------------------------
|
43
43
|
|
44
|
-
If you prefer to learn by example, see the [examples](examples) folder for
|
44
|
+
If you prefer to learn by example, see the [examples](examples#examples) folder for
|
45
45
|
several use cases. Each example subfolder contains the command to run, the
|
46
46
|
relevant files, and the expected output.
|
47
47
|
|
@@ -85,15 +85,28 @@ The space after `filename` is optional.
|
|
85
85
|
|
86
86
|
|
87
87
|
|
88
|
+
### Compile an Entire Folder
|
89
|
+
|
90
|
+
![kojo](images/features-dir.svg)
|
91
|
+
|
92
|
+
Process a folder containing templates and `@imports`, and generate a mirror
|
93
|
+
output folder, with all the variables and `@imports` evaluated.
|
94
|
+
|
95
|
+
|
96
|
+
|
88
97
|
### One to Many Generation
|
89
98
|
|
90
99
|
![kojo](images/features-config.svg)
|
91
100
|
|
92
|
-
|
93
|
-
|
101
|
+
Using the `kojo config` command together with a simple definitions file, you
|
102
|
+
can:
|
103
|
+
|
104
|
+
1. Generate multiple output files based on a single template file
|
105
|
+
2. Generate multiple output directories, based on a single source directory.
|
106
|
+
|
107
|
+
To achieve this, you need to:
|
94
108
|
|
95
|
-
1. Create the configuration template
|
96
|
-
where appropriate.
|
109
|
+
1. Create the configuration template or directory of templates.
|
97
110
|
2. Create a configuration YAML file using this syntax:
|
98
111
|
|
99
112
|
```yaml
|
@@ -109,15 +122,22 @@ output:
|
|
109
122
|
argument2: value
|
110
123
|
```
|
111
124
|
|
125
|
+
When using a folder as input, simply provide the folder name in the `input`
|
126
|
+
property, and instead of providing desired output filenames in the `output`
|
127
|
+
property, provide desired output directories:
|
112
128
|
|
129
|
+
```yaml
|
130
|
+
input: base
|
113
131
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
Process a folder containing templates and `@imports`, and generate a mirror
|
119
|
-
output folder, with all the variables and `@imports` evaluated.
|
132
|
+
output:
|
133
|
+
app1:
|
134
|
+
argument1: value
|
135
|
+
argument2: value
|
120
136
|
|
137
|
+
app2:
|
138
|
+
argument1: value
|
139
|
+
argument2: value
|
140
|
+
```
|
121
141
|
|
122
142
|
|
123
143
|
### Conditions and Loops with ERB
|
data/bin/kojo
CHANGED
data/lib/kojo.rb
CHANGED
data/lib/kojo/cli.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Kojo
|
2
|
+
# The Collection class is a wrapper around the {Template} object. It
|
3
|
+
# provides a mechanism for processing an entire directory of templates.
|
4
|
+
class Collection
|
5
|
+
attr_reader :dir
|
6
|
+
attr_accessor :import_base
|
7
|
+
|
8
|
+
def initialize(dir)
|
9
|
+
@dir = dir
|
10
|
+
@import_base = dir
|
11
|
+
end
|
12
|
+
|
13
|
+
def render(args={}, &block)
|
14
|
+
files.each do |file|
|
15
|
+
handle file, args, &block
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def handle(file, args={})
|
22
|
+
template = Template.new file
|
23
|
+
template.import_base = import_base
|
24
|
+
|
25
|
+
path = file.sub(/#{dir}\//, '')
|
26
|
+
|
27
|
+
yield path, template.render(args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def files
|
31
|
+
return @files if @files
|
32
|
+
raise Kojo::NotFoundError, "Directory not found: #{dir}" unless Dir.exist? dir
|
33
|
+
raise Kojo::NotFoundError, "Directory is empty: #{dir}" if Dir.empty? dir
|
34
|
+
|
35
|
+
@files = Dir["#{dir}/**/*"].reject { |f| File.directory? f }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/kojo/commands/config.rb
CHANGED
@@ -2,15 +2,17 @@ require 'fileutils'
|
|
2
2
|
require 'mister_bin'
|
3
3
|
|
4
4
|
module Kojo::Commands
|
5
|
+
# Handle calls to the +kojo config+ command
|
5
6
|
class ConfigCmd < MisterBin::Command
|
6
|
-
attr_reader :gen, :outdir, :opts
|
7
|
+
attr_reader :gen, :outdir, :opts, :import_base, :config_file
|
7
8
|
|
8
9
|
help "Generate based on instructions from a config file"
|
9
10
|
|
10
|
-
usage "kojo config CONFIG [--save DIR --args FILE] [ARGS...]"
|
11
|
+
usage "kojo config CONFIG [--save DIR --imports DIR --args FILE] [ARGS...]"
|
11
12
|
usage "kojo config (-h|--help)"
|
12
13
|
|
13
14
|
option "-s --save DIR", "Save output to directory instead of printing"
|
15
|
+
option "-i --imports DIR", "Specify base directory for @import directives"
|
14
16
|
option "-a --args FILE", "Load arguments from YAML file"
|
15
17
|
|
16
18
|
param "ARGS", "Optional key=value pairs"
|
@@ -21,9 +23,10 @@ module Kojo::Commands
|
|
21
23
|
example "kojo config config.yml -s output --args args.yml"
|
22
24
|
|
23
25
|
def run(args)
|
24
|
-
@
|
26
|
+
@config_file = args['CONFIG']
|
25
27
|
@outdir = args['--save']
|
26
28
|
@opts = args['ARGS'].args_to_hash
|
29
|
+
@import_base = args['--imports']
|
27
30
|
argfile = args['--args']
|
28
31
|
|
29
32
|
if argfile
|
@@ -35,7 +38,10 @@ module Kojo::Commands
|
|
35
38
|
end
|
36
39
|
|
37
40
|
def run!
|
38
|
-
|
41
|
+
config = Kojo::Config.new config_file
|
42
|
+
config.import_base = import_base if import_base
|
43
|
+
|
44
|
+
config.generate opts do |file, output|
|
39
45
|
handle file, output
|
40
46
|
end
|
41
47
|
end
|
data/lib/kojo/commands/dir.rb
CHANGED
@@ -1,30 +1,31 @@
|
|
1
1
|
require 'mister_bin'
|
2
2
|
|
3
3
|
module Kojo::Commands
|
4
|
+
# Handle calls to the +kojo dir+ command
|
4
5
|
class DirCmd < MisterBin::Command
|
5
6
|
attr_reader :opts, :indir, :outdir, :import_base
|
6
7
|
|
7
8
|
help "Compile a folder of templates to a similar output folder"
|
8
9
|
|
9
|
-
usage "kojo dir INDIR [--save DIR --
|
10
|
+
usage "kojo dir INDIR [--save DIR --imports DIR --args FILE] [ARGS...]"
|
10
11
|
usage "kojo dir (-h|--help)"
|
11
12
|
|
12
13
|
option "-s --save DIR", "Save output to directory instead of printing"
|
13
|
-
option "-i --
|
14
|
+
option "-i --imports DIR", "Specify base directory for @import directives"
|
14
15
|
option "-a --args FILE", "Load arguments from YAML file"
|
15
16
|
|
16
17
|
param "ARGS", "Optional key=value pairs"
|
17
18
|
|
18
19
|
example "kojo dir indir"
|
19
20
|
example "kojo dir in --save out env=production"
|
20
|
-
example "kojo dir in --save out --
|
21
|
+
example "kojo dir in --save out --imports snippets env=production"
|
21
22
|
example "kojo dir in -s out -i snippets -a args.yml"
|
22
23
|
|
23
24
|
def run(args)
|
24
25
|
@opts = args['ARGS'].args_to_hash
|
25
26
|
@indir = args['INDIR']
|
26
27
|
@outdir = args['--save']
|
27
|
-
@import_base = args['--
|
28
|
+
@import_base = args['--imports']
|
28
29
|
argfile = args['--args']
|
29
30
|
|
30
31
|
if argfile
|
@@ -37,32 +38,32 @@ module Kojo::Commands
|
|
37
38
|
|
38
39
|
private
|
39
40
|
|
40
|
-
def files
|
41
|
-
@files ||= Dir["#{indir}/**/*"].reject { |file| File.directory? file }
|
42
|
-
end
|
43
|
-
|
44
41
|
def run!
|
45
|
-
|
46
|
-
|
42
|
+
collection = Kojo::Collection.new @indir
|
43
|
+
collection.import_base = import_base if import_base
|
44
|
+
|
45
|
+
if outdir
|
46
|
+
write collection
|
47
|
+
else
|
48
|
+
show collection
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
def show(collection)
|
53
|
+
collection.render @opts do |file, output|
|
54
|
+
say "\n!txtgrn!# #{file}"
|
55
|
+
say output
|
56
|
+
end
|
57
|
+
end
|
54
58
|
|
55
|
-
|
59
|
+
def write(collection)
|
60
|
+
collection.render @opts do |file, output|
|
56
61
|
save file, output
|
57
|
-
else
|
58
|
-
outpath = file.sub(/#{indir}/, '')
|
59
|
-
say "\n!txtgrn!# #{outpath}"
|
60
|
-
say output
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
65
|
def save(file, output)
|
65
|
-
outpath =
|
66
|
+
outpath = "#{outdir}/#{file}"
|
66
67
|
dir = File.dirname outpath
|
67
68
|
FileUtils.mkdir_p dir unless Dir.exist? dir
|
68
69
|
File.write outpath, output
|
data/lib/kojo/commands/file.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
require 'mister_bin'
|
2
2
|
|
3
3
|
module Kojo::Commands
|
4
|
+
# Handle calls to the +kojo file+ command
|
4
5
|
class FileCmd < MisterBin::Command
|
5
|
-
attr_reader :opts, :outfile, :infile
|
6
|
+
attr_reader :opts, :outfile, :infile, :import_base
|
6
7
|
|
7
8
|
help "Compile a file from a template"
|
8
9
|
|
9
|
-
usage "kojo file INFILE [--save FILE --args FILE] [ARGS...]"
|
10
|
+
usage "kojo file INFILE [--save FILE --imports DIR --args FILE] [ARGS...]"
|
10
11
|
usage "kojo file (-h|--help)"
|
11
12
|
|
12
13
|
option "-s --save FILE", "Save to file instead of printing"
|
14
|
+
option "-i --imports DIR", "Specify base directory for @import directives"
|
13
15
|
option "-a --args FILE", "Load arguments from YAML file"
|
14
16
|
|
15
17
|
param "ARGS", "Optional key=value pairs"
|
@@ -23,6 +25,7 @@ module Kojo::Commands
|
|
23
25
|
@opts = args['ARGS'].args_to_hash
|
24
26
|
@outfile = args['--save']
|
25
27
|
@infile = args['INFILE']
|
28
|
+
@import_base = args['--imports']
|
26
29
|
argfile = args['--args']
|
27
30
|
|
28
31
|
if argfile
|
@@ -34,7 +37,9 @@ module Kojo::Commands
|
|
34
37
|
end
|
35
38
|
|
36
39
|
def run!
|
37
|
-
|
40
|
+
template = Kojo::Template.new infile
|
41
|
+
template.import_base = import_base if import_base
|
42
|
+
output = template.render(opts)
|
38
43
|
|
39
44
|
if outfile
|
40
45
|
File.write outfile, output
|
data/lib/kojo/config.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Kojo
|
4
|
+
# The Config class handles multiple template generation from a
|
5
|
+
# definitions YAML file.
|
6
|
+
class Config
|
7
|
+
attr_reader :config_file, :outdir
|
8
|
+
attr_accessor :import_base
|
9
|
+
|
10
|
+
def initialize(config_file)
|
11
|
+
@config_file = config_file
|
12
|
+
@import_base = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate(opts={}, &block)
|
16
|
+
if directory_mode?
|
17
|
+
generate_from_dir opts, &block
|
18
|
+
else
|
19
|
+
generate_from_file opts, &block
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def generate_from_file(opts)
|
26
|
+
config['output'].each do |target, config_opts|
|
27
|
+
local_opts = opts.merge config_opts.symbolize_keys
|
28
|
+
|
29
|
+
template = Template.new source
|
30
|
+
template.import_base = import_base if import_base
|
31
|
+
|
32
|
+
yield target, template.render(local_opts)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_from_dir(opts)
|
37
|
+
config['output'].each do |dir, config_opts|
|
38
|
+
local_opts = opts.merge config_opts.symbolize_keys
|
39
|
+
|
40
|
+
collection = Collection.new source
|
41
|
+
collection.import_base = import_base if import_base
|
42
|
+
|
43
|
+
collection.render(local_opts) do |file, output|
|
44
|
+
yield "#{dir}/#{file}", output
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def base_dir
|
50
|
+
@base_dir ||= File.dirname config_file
|
51
|
+
end
|
52
|
+
|
53
|
+
def directory_mode?
|
54
|
+
File.directory? source
|
55
|
+
end
|
56
|
+
|
57
|
+
def source
|
58
|
+
"#{base_dir}/#{config['input']}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def config
|
62
|
+
@config ||= YAML.load_file config_file
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
class String
|
2
|
+
# Convert a string to the most appropriate type
|
2
3
|
def to_typed
|
3
4
|
if self =~ /\A[+-]?\d+\Z/
|
4
5
|
self.to_i
|
@@ -6,8 +7,8 @@ class String
|
|
6
7
|
elsif self =~ /\A[+-]?\d+\.\d+\Z/
|
7
8
|
self.to_f
|
8
9
|
|
9
|
-
elsif %w[yes no true false].include?
|
10
|
-
%w[yes true].include?
|
10
|
+
elsif %w[yes no true false].include? downcase
|
11
|
+
%w[yes true].include? downcase
|
11
12
|
|
12
13
|
else
|
13
14
|
self
|
data/lib/kojo/template.rb
CHANGED
@@ -2,30 +2,53 @@ require 'erb'
|
|
2
2
|
require 'ostruct'
|
3
3
|
|
4
4
|
module Kojo
|
5
|
+
# The Template class handles a single template file, and processes it for:
|
6
|
+
# - Variables (using +%{var}+ syntax)
|
7
|
+
# - ERB
|
8
|
+
# - +@import+ statements
|
5
9
|
class Template
|
6
|
-
attr_reader :file, :extension, :
|
10
|
+
attr_reader :file, :extension, :dir, :args
|
7
11
|
attr_accessor :import_base
|
8
12
|
|
9
|
-
def initialize(file
|
13
|
+
def initialize(file)
|
10
14
|
@file = file
|
11
|
-
@
|
12
|
-
@extension = file[/(\..*)$/]
|
15
|
+
@extension = File.extname file
|
13
16
|
@dir = File.dirname file
|
14
17
|
@import_base = dir
|
15
18
|
end
|
16
19
|
|
17
|
-
def render
|
18
|
-
|
20
|
+
def render(args={})
|
21
|
+
@args = args
|
22
|
+
evaluate file
|
19
23
|
end
|
20
24
|
|
21
25
|
private
|
22
26
|
|
23
|
-
def evaluate(file
|
24
|
-
content =
|
27
|
+
def evaluate(file)
|
28
|
+
content = read_file file
|
29
|
+
content = eval_erb content
|
30
|
+
content = eval_vars content
|
31
|
+
content = eval_imports content
|
32
|
+
content
|
33
|
+
end
|
34
|
+
|
35
|
+
def read_file(file)
|
36
|
+
raise Kojo::NotFoundError, "File not found: #{file}" unless File.exist? file
|
37
|
+
File.read file
|
38
|
+
end
|
39
|
+
|
40
|
+
def eval_vars(content)
|
41
|
+
content % args
|
42
|
+
rescue ArgumentError, KeyError => e
|
43
|
+
raise Kojo::TemplateError, "#{e.message}\nin: #{file}"
|
44
|
+
end
|
25
45
|
|
26
|
-
|
27
|
-
|
28
|
-
|
46
|
+
def eval_erb(content)
|
47
|
+
erb content, args
|
48
|
+
rescue RuntimeError => e
|
49
|
+
raise Kojo::TemplateError, "Invalid Ruby code #{e.message}\nin: #{file}"
|
50
|
+
rescue SyntaxError => e
|
51
|
+
raise Kojo::TemplateError, "#{e.message}\nin: #{file}"
|
29
52
|
end
|
30
53
|
|
31
54
|
def eval_imports(content)
|
@@ -52,7 +75,7 @@ module Kojo
|
|
52
75
|
def import(file, import_args={})
|
53
76
|
filename = File.expand_path "#{file}#{extension}", import_base
|
54
77
|
all_args = args.merge import_args
|
55
|
-
self.class.new(filename
|
78
|
+
self.class.new(filename).render(all_args)
|
56
79
|
end
|
57
80
|
|
58
81
|
def erb(template, vars)
|
data/lib/kojo/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kojo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Danny Ben Shitrit
|
@@ -134,13 +134,15 @@ files:
|
|
134
134
|
- bin/kojo
|
135
135
|
- lib/kojo.rb
|
136
136
|
- lib/kojo/cli.rb
|
137
|
+
- lib/kojo/collection.rb
|
137
138
|
- lib/kojo/commands/config.rb
|
138
139
|
- lib/kojo/commands/dir.rb
|
139
140
|
- lib/kojo/commands/file.rb
|
141
|
+
- lib/kojo/config.rb
|
142
|
+
- lib/kojo/exceptions.rb
|
140
143
|
- lib/kojo/extensions/array.rb
|
141
144
|
- lib/kojo/extensions/hash.rb
|
142
145
|
- lib/kojo/extensions/string.rb
|
143
|
-
- lib/kojo/generator.rb
|
144
146
|
- lib/kojo/template.rb
|
145
147
|
- lib/kojo/version.rb
|
146
148
|
homepage: https://github.com/dannyben/kojo
|
data/lib/kojo/generator.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
module Kojo
|
4
|
-
class Generator
|
5
|
-
attr_reader :config_file, :outdir
|
6
|
-
|
7
|
-
def initialize(config_file)
|
8
|
-
@config_file = config_file
|
9
|
-
end
|
10
|
-
|
11
|
-
def generate(opts={})
|
12
|
-
base_dir = File.dirname config_file
|
13
|
-
infile = "#{base_dir}/#{config['input']}"
|
14
|
-
|
15
|
-
config['output'].each do |outfile, config_opts|
|
16
|
-
local_opts = opts.merge config_opts.symbolize_keys
|
17
|
-
output = render infile, local_opts
|
18
|
-
yield outfile, output
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def config
|
25
|
-
@config ||= YAML.load_file config_file
|
26
|
-
end
|
27
|
-
|
28
|
-
def render(infile, opts={})
|
29
|
-
Template.new(infile, opts).render
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|