turple 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +28 -7
- data/lib/turple.rb +22 -11
- data/lib/turple/cli.rb +6 -9
- data/lib/turple/data.rb +2 -4
- data/lib/turple/interpolate.rb +1 -1
- data/lib/turple/template.rb +103 -83
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OTllNzk2ZWQ3MTY0NDcwNjk3YzczODY1OTVkNjg2ODNiMmMxZTdmZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YjY5ZjM3NDMwZTZhNTkyMGVmYmFmNWRiZDAyZGViMTE3ZWZhOWQ2Mg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
N2MzMzIyZTc2NjJkYmI0MTkwZTgwY2Y0ZmM2MmU3NDYwZGMyODU5NDFhN2Rj
|
10
|
+
MDc2OWY0ZTI2MGNkZDQ2ZTNlMzAwODA2MjU3NTY0NmY4MDY0NzFjMTc4ZGY3
|
11
|
+
ODE2YTYzNjhiZjQ1OTM3MDAxMGM2MzE1YmYyNTlmMThmMTBhOTU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ODAyZDIxN2FkNDkyNzZhMWEyNTRiZDg4ZmMyYjBhODQ2MmVhMjNiNzZhMGRi
|
14
|
+
YTNlMWYyMjFkMTA1MWE3ZjExOTlhMmYzZjZiYjVkMGRkZmQ4Y2VmYTM1MTNk
|
15
|
+
YmIzODVkZTNiNTRhNGNlMmEyMTk4NDZlMzhjMmY2NGQ4MzY4YjQ=
|
data/README.md
CHANGED
@@ -7,6 +7,22 @@ Quick project templating, with optional cli wizard support
|
|
7
7
|
|
8
8
|
Turple can take a custom template and use it to bootstrap projects structures you commonly use instead of **copy/pasting** an old project and **find/replacing** to make it a new project.
|
9
9
|
|
10
|
+
### Install
|
11
|
+
```sh
|
12
|
+
gem install turple
|
13
|
+
```
|
14
|
+
|
15
|
+
Optionally you can create a `Turplefile` in your home directory *(~/Turplefile)* and include your own custom sources, and even common template data. This will prevent you from having to define your sources everytime you create a new project.
|
16
|
+
|
17
|
+
```yaml
|
18
|
+
sources:
|
19
|
+
my_remote_source: my_github_user/turple-templates
|
20
|
+
my_local_source: ~/Documents/turple-templates
|
21
|
+
data:
|
22
|
+
developer:
|
23
|
+
name: Jane Doe
|
24
|
+
```
|
25
|
+
|
10
26
|
### Usage
|
11
27
|
|
12
28
|
I always make projects the same way. There are a bunch of tools for (supposedly) making this easier/faster, but I don't like any of them. They are either too opinionated or too limiting. This is what I like.
|
@@ -17,7 +33,7 @@ Turple is best used from a command line, but it can be used directly in ruby as
|
|
17
33
|
|
18
34
|
### CLI
|
19
35
|
|
20
|
-
Turple requires a path to a template, and an optional destination. If no destination is passed, it will put everything in a `turple` folder
|
36
|
+
Turple requires a path to a template, and an optional destination. If no destination is passed, it will put everything in a `turple` folder in your current working directory.
|
21
37
|
|
22
38
|
```sh
|
23
39
|
turple --template /path/to/template --destination my_new_project_name
|
@@ -26,18 +42,23 @@ turple --template /path/to/template --destination my_new_project_name
|
|
26
42
|
turple -t /path/to/template -d my_new_project_name
|
27
43
|
```
|
28
44
|
|
29
|
-
Turple will scan the template, determine what data is needed to process it, and prompt you for any missing data. If you wanted to run turple without the wizard, just
|
30
|
-
|
31
|
-
### Turplefile
|
32
|
-
|
33
|
-
`Turplefile` files are yaml formatted files that provided various information to turple. Assuming our template requires a single piece of information called `foo`, our destination Turplefile could look something like this.
|
45
|
+
Turple will scan the template, determine what data is needed to process it, and prompt you for any missing data. If you wanted to run turple without the wizard, just put a `Turplefile` into your destination directory with the necessary data. Assuming our template requires a single piece of information called `foo`, our destination Turplefile could look something like this.
|
34
46
|
|
35
47
|
```yaml
|
36
48
|
data:
|
37
49
|
foo: bar
|
38
50
|
```
|
39
51
|
|
40
|
-
|
52
|
+
### Turplefile
|
53
|
+
|
54
|
+
`Turplefile` files are yaml formatted files that provided various information to turple. Turple checks in multiple locations for a Turplefile.
|
55
|
+
|
56
|
+
* Home Directory *(~/Turplefile)*
|
57
|
+
* Define your own custom defaults... Set your sources, preferred template configuration, and even common template data *(e.g. developer.name)*
|
58
|
+
* Template
|
59
|
+
* Templates require a Turplefile with a configuration *(esp if different from the turple defaults)* and an optional data map for use with the wizard.
|
60
|
+
* Destination
|
61
|
+
* This file can have preset data (good for bypassing the wizard)
|
41
62
|
|
42
63
|
### Turple Templates
|
43
64
|
|
data/lib/turple.rb
CHANGED
@@ -18,6 +18,7 @@ class Turple
|
|
18
18
|
|
19
19
|
# Turple user configuration defaults
|
20
20
|
@@turpleobject = {
|
21
|
+
:interactive => false,
|
21
22
|
:template => '',
|
22
23
|
:data => {},
|
23
24
|
:data_map => {},
|
@@ -100,7 +101,8 @@ class Turple
|
|
100
101
|
# allows helper accessors for turpleobject
|
101
102
|
#
|
102
103
|
def self.method_missing method
|
103
|
-
self.turpleobject[method]
|
104
|
+
value = self.turpleobject[method]
|
105
|
+
defined?(value) ? value : super
|
104
106
|
end
|
105
107
|
|
106
108
|
# Read yaml turplefile and add contents to the turpleobject
|
@@ -129,34 +131,43 @@ class Turple
|
|
129
131
|
private
|
130
132
|
|
131
133
|
def initialize template_path, data_hash = {}, configuration_hash = {}
|
132
|
-
#
|
133
|
-
# load home & template turplefile first for possible additional sources
|
134
|
+
# load home turplefile
|
134
135
|
Turple.load_turplefile File.join(File.expand_path('~'), 'Turplefile')
|
135
|
-
|
136
|
+
|
137
|
+
# create sources
|
136
138
|
Turple.sources.each do |source_name, source_path|
|
137
139
|
Turple::Source.new source_name, source_path
|
138
140
|
end
|
139
141
|
|
140
|
-
#
|
141
|
-
|
142
|
-
|
143
|
-
|
142
|
+
# update turpleobject with initialized arguments
|
143
|
+
Turple.turpleobject = {
|
144
|
+
:template => template_path,
|
145
|
+
:data => data_hash,
|
146
|
+
:configuration => configuration_hash
|
147
|
+
}
|
148
|
+
|
149
|
+
# initialize template after sources are created
|
150
|
+
@template = Turple::Template.new template_path, Turple.interactive
|
151
|
+
|
152
|
+
# set destination and load Turplefile
|
153
|
+
@destination_path = File.expand_path Turple.configuration[:destination]
|
154
|
+
Turple.load_turplefile File.join(@destination_path, 'Turplefile')
|
144
155
|
|
145
156
|
# collect data
|
146
157
|
data_hash = Turple.data.deep_merge data_hash
|
147
158
|
data_map_hash = Turple.data_map
|
159
|
+
configuration_hash = Turple.configuration.deep_merge configuration_hash
|
148
160
|
|
149
|
-
if
|
161
|
+
if Turple.interactive
|
150
162
|
S.ay 'Saving to: ', :preset => :prompt, :newline => false
|
151
163
|
S.ay @destination_path
|
152
164
|
end
|
153
165
|
|
154
166
|
# Initialize components
|
155
|
-
@template = Turple::Template.new template_path, configuration_hash
|
156
167
|
@data = Turple::Data.new @template.required_data, data_hash, data_map_hash
|
157
168
|
@interpolate = Turple::Interpolate.new @template, @data, @destination_path
|
158
169
|
|
159
|
-
output_summary if
|
170
|
+
output_summary if Turple.interactive
|
160
171
|
end
|
161
172
|
|
162
173
|
def output_summary
|
data/lib/turple/cli.rb
CHANGED
@@ -5,17 +5,14 @@ class Turple::Cli < Thor
|
|
5
5
|
option :template, :type => :string, :aliases => ['-t'], :desc => 'Path to, or name of, a turple template.'
|
6
6
|
option :destination, :type => :string, :aliases => ['-d'], :desc => 'Path to save interpolated template to.'
|
7
7
|
def ate
|
8
|
-
#
|
9
|
-
Turple.turpleobject = {
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
destination: options['destination'] || Turple.configuration[:destination],
|
14
|
-
}
|
15
|
-
}
|
8
|
+
# enable interactive mode
|
9
|
+
Turple.turpleobject = { :interactive => true }
|
10
|
+
|
11
|
+
# dont pass a nil destination
|
12
|
+
configuration_hash = options['destination'] ? { :destination => options['destination'] } : {}
|
16
13
|
|
17
14
|
# initialize turple
|
18
|
-
Turple.ate
|
15
|
+
Turple.ate options['template'], {}, configuration_hash
|
19
16
|
end
|
20
17
|
|
21
18
|
default_task :ate
|
data/lib/turple/data.rb
CHANGED
@@ -18,10 +18,8 @@ private
|
|
18
18
|
prompt_for_data missing_data
|
19
19
|
end
|
20
20
|
|
21
|
-
#
|
22
|
-
Turple.turpleobject = {
|
23
|
-
:data => @provided_data
|
24
|
-
}
|
21
|
+
# update turpleobject with complete data
|
22
|
+
Turple.turpleobject = { :data => @provided_data }
|
25
23
|
end
|
26
24
|
|
27
25
|
# populate missing data map values to match required data
|
data/lib/turple/interpolate.rb
CHANGED
data/lib/turple/template.rb
CHANGED
@@ -9,41 +9,82 @@ class Turple::Template
|
|
9
9
|
|
10
10
|
private
|
11
11
|
|
12
|
-
def initialize
|
13
|
-
|
14
|
-
|
15
|
-
# validate
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
def initialize template, interactive = false
|
13
|
+
path = get_template_path template
|
14
|
+
|
15
|
+
# validate and set path before configuration
|
16
|
+
if valid_path? path
|
17
|
+
@path = path
|
18
|
+
else
|
19
|
+
if interactive
|
20
|
+
until @path
|
21
|
+
prompt_for_path
|
22
|
+
end
|
20
23
|
else
|
21
24
|
raise S.ay "Invalid Template Path `#{path}`", :error
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
25
|
-
#
|
28
|
+
# with a valid path, load the turplefile
|
29
|
+
Turple.load_turplefile File.join(@path, 'Turplefile')
|
30
|
+
|
31
|
+
# validate configuration after path is validated and template Turplefile is loaded
|
32
|
+
valid_configuration? Turple.configuration
|
33
|
+
|
34
|
+
# set variables after validating path
|
35
|
+
@name = File.basename @path
|
26
36
|
@required_data = scan_for_data @path
|
27
|
-
|
37
|
+
end
|
38
|
+
|
39
|
+
# Look for a template path with a user provided template name or path
|
40
|
+
#
|
41
|
+
# @param template [String] template name, source && template name, or system path
|
42
|
+
# @return [String] valid template path or nil if none is found
|
43
|
+
#
|
44
|
+
def get_template_path template
|
45
|
+
return nil unless template
|
46
|
+
|
47
|
+
# with source included in template path...
|
48
|
+
if template.include? SOURCE_TEMPLATE_SPLITTER
|
49
|
+
# split source from template
|
50
|
+
source_template = template.split SOURCE_TEMPLATE_SPLITTER
|
51
|
+
|
52
|
+
# create new source
|
53
|
+
begin
|
54
|
+
source = Turple::Source.new source_template[1], source_template[0]
|
55
|
+
rescue
|
56
|
+
return nil
|
57
|
+
end
|
58
|
+
|
59
|
+
# look up template path from new source
|
60
|
+
source.template_paths[source_template[1]]
|
61
|
+
|
62
|
+
# if just the template name/path is passed...
|
63
|
+
else
|
64
|
+
# check for template name in existing sources or treat it as a local path
|
65
|
+
Turple::Source.find_template_path(template) || File.expand_path(template) || nil
|
66
|
+
end
|
28
67
|
end
|
29
68
|
|
30
69
|
# Scan a path and determine the required data needed to interpolate it
|
70
|
+
#
|
31
71
|
# @param template_path [String] path to a template file
|
32
72
|
# @return [Hash] a hash of all the data needed
|
33
73
|
#
|
34
74
|
def scan_for_data template_path
|
75
|
+
configuration = Turple.configuration
|
35
76
|
required_data = {}
|
36
77
|
|
37
78
|
Find.find template_path do |path|
|
38
79
|
if File.file?(path)
|
39
80
|
|
40
81
|
# process file paths
|
41
|
-
path_regex = Regexp.new
|
82
|
+
path_regex = Regexp.new configuration[:path_regex]
|
42
83
|
if path =~ path_regex
|
43
84
|
capture_groups = path.scan(path_regex).flatten
|
44
85
|
|
45
86
|
capture_groups.each do |group|
|
46
|
-
group_attributes = group.split(
|
87
|
+
group_attributes = group.split(configuration[:path_separator])
|
47
88
|
group_attributes_hash = group_attributes.reverse.inject(true) { |value, key| { key.downcase.to_sym => value } }
|
48
89
|
|
49
90
|
required_data.deep_merge! group_attributes_hash
|
@@ -51,12 +92,12 @@ private
|
|
51
92
|
end
|
52
93
|
|
53
94
|
# process file contents
|
54
|
-
content_regex = Regexp.new
|
55
|
-
if path =~ /\.#{Regexp.escape(
|
95
|
+
content_regex = Regexp.new configuration[:content_regex]
|
96
|
+
if path =~ /\.#{Regexp.escape(configuration[:file_ext])}$/
|
56
97
|
capture_groups = File.read(path).scan(content_regex).flatten
|
57
98
|
|
58
99
|
capture_groups.each do |group|
|
59
|
-
group_attributes = group.split(
|
100
|
+
group_attributes = group.split(configuration[:content_separator])
|
60
101
|
group_attributes_hash = group_attributes.reverse.inject(true) { |value, key| { key.downcase.to_sym => value } }
|
61
102
|
|
62
103
|
required_data.deep_merge! group_attributes_hash
|
@@ -67,94 +108,73 @@ private
|
|
67
108
|
|
68
109
|
# check that the template requires data
|
69
110
|
if required_data.empty?
|
70
|
-
|
111
|
+
S.ay 'No Required Data - Nothing found to interpolate. Make sure your configuration matches your template.', :error
|
112
|
+
exit
|
71
113
|
end
|
72
114
|
|
73
115
|
return required_data
|
74
116
|
end
|
75
117
|
|
76
|
-
# check that the path is a valid template
|
77
|
-
# @return [Boolean]
|
78
|
-
#
|
79
|
-
def valid_path? potential_path
|
80
|
-
# with source included in template path...
|
81
|
-
new_path = if potential_path.include? SOURCE_TEMPLATE_SPLITTER
|
82
|
-
# split source from template
|
83
|
-
source_template = potential_path.split SOURCE_TEMPLATE_SPLITTER
|
84
|
-
|
85
|
-
# create new source
|
86
|
-
begin
|
87
|
-
Turple::Source.new source_template[1], source_template[0]
|
88
|
-
rescue
|
89
|
-
return false
|
90
|
-
end
|
91
|
-
|
92
|
-
# look up template path from new source
|
93
|
-
Turple::Source.find_template_path source_template[1], source_template[1]
|
94
|
-
|
95
|
-
# if just the template name/path is passed...
|
96
|
-
else
|
97
|
-
# check for template name in existing sources or treat it as a local path
|
98
|
-
Turple::Source.find_template_path(potential_path) || File.expand_path(potential_path)
|
99
|
-
end
|
100
|
-
|
101
|
-
# set path var if new path is a valid template
|
102
|
-
if !new_path.nil? && File.directory?(new_path) && File.file?(File.join(new_path, 'Turplefile'))
|
103
|
-
@path = new_path
|
104
|
-
return true
|
105
|
-
else
|
106
|
-
return false
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
118
|
# prompt the user for a template path until a vaid one is entered
|
111
119
|
# @return [String] valid template path
|
112
120
|
#
|
113
121
|
def prompt_for_path
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
end
|
122
|
+
A.sk 'Enter a path to a Turple Template', :preset => :prompt, :readline => true do |response|
|
123
|
+
path = get_template_path response
|
124
|
+
@path = path if valid_path? path
|
118
125
|
end
|
126
|
+
end
|
119
127
|
|
120
|
-
|
128
|
+
# Check that a path is a valid template
|
129
|
+
#
|
130
|
+
# @param path [String] file system path to a proposed template directory
|
131
|
+
# @return [Boolean]
|
132
|
+
#
|
133
|
+
def valid_path? path
|
134
|
+
!path.nil? && File.directory?(path) && File.file?(File.join(path, 'Turplefile'))
|
121
135
|
end
|
122
136
|
|
123
137
|
# check the configuration is valid
|
124
|
-
# @return [Boolean]
|
125
138
|
#
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
139
|
+
# @param [Hash] a configuration hash
|
140
|
+
# @return [Boolean] true or exit
|
141
|
+
#
|
142
|
+
def valid_configuration? configuration
|
143
|
+
begin
|
144
|
+
# check that a configuration exists
|
145
|
+
if configuration.empty?
|
146
|
+
raise S.ay 'No Configuration Found', :error
|
147
|
+
end
|
131
148
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
149
|
+
# check that a configuration values are valid
|
150
|
+
#
|
151
|
+
# make sure the string is a valid extension with no period's in it
|
152
|
+
if !configuration[:file_ext].is_a?(String) ||
|
153
|
+
configuration[:file_ext] =~ /\./
|
154
|
+
raise S.ay "`file_ext` is invalid. See README for requirements.", :error
|
155
|
+
end
|
139
156
|
|
140
|
-
|
141
|
-
|
142
|
-
|
157
|
+
if !configuration[:path_separator].is_a?(String)
|
158
|
+
raise S.ay "`path_separator` is invalid. See README for requirements.", :error
|
159
|
+
end
|
143
160
|
|
144
|
-
|
145
|
-
|
146
|
-
|
161
|
+
if !configuration[:content_separator].is_a?(String)
|
162
|
+
raise S.ay "`content_separator` is invalid. See README for requirements.", :error
|
163
|
+
end
|
147
164
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
165
|
+
# make sure it contains the path separator in the capture group
|
166
|
+
if !(configuration[:path_regex] =~ /\(.*#{Regexp.escape(configuration[:path_separator])}.*\)/)
|
167
|
+
raise S.ay "`path_regex` invalid. See README for requirements.", :error
|
168
|
+
end
|
152
169
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
170
|
+
# make sure it contains the path separator in the capture group
|
171
|
+
if !(configuration[:content_regex] =~ /\(.*#{Regexp.escape(configuration[:content_separator])}.*\)/)
|
172
|
+
raise S.ay "`content_regex` invalid. See README for requirements.", :error
|
173
|
+
end
|
157
174
|
|
158
|
-
|
175
|
+
return true
|
176
|
+
rescue
|
177
|
+
exit
|
178
|
+
end
|
159
179
|
end
|
160
180
|
end
|