snp 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +104 -0
- data/lib/snp.rb +9 -0
- data/lib/snp/cli.rb +226 -0
- data/lib/snp/compiler.rb +58 -0
- data/lib/snp/data.rb +50 -0
- data/lib/snp/path.rb +83 -0
- data/lib/snp/template.rb +62 -0
- data/lib/snp/template_context.rb +85 -0
- data/lib/snp/version.rb +3 -0
- data/test/snp/cli_test.rb +99 -0
- data/test/snp/compiler_test.rb +42 -0
- data/test/snp/data_test.rb +30 -0
- data/test/snp/path_test.rb +47 -0
- data/test/snp/template_context_test.rb +52 -0
- data/test/snp/template_test.rb +37 -0
- data/test/test_helper.rb +15 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 49d5d8be74b2f7914fd8a8eabe8e3b886c70d843
|
4
|
+
data.tar.gz: 7fc0270b98da93a2ff118206b53d69828fa33c02
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6b13774f35b7f26b96be00454897bdc9954e0896a775fdae12b6f9f53b81d5f2ec38cdb1f2ed318de677fb0f5e92b76ddea5d1fc5ecd11eb20d56ed8f3b08302
|
7
|
+
data.tar.gz: 35dafdd03b76034b47215c682fb5a4e540752c379318026d3fe58b58c0779af0cb82e8937cf6f18f4ff29e8d2263273b61ce8aebfa20aad52dfbaed5c95014d9
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2014 Renato Mascarenhas http://renatomascarenhas.name/
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# snp - easy snippets for everyone
|
2
|
+
|
3
|
+
`snp` is a tool to allow easy snippet creation, in an automated and reusable manner.
|
4
|
+
How many times did you create that small HTML document to test out if something worked
|
5
|
+
quite the way you thought it did? `snp`'s goal is to free the user from the creation
|
6
|
+
of all boilerplate involved in the creation of such snippets, allowing the programmer
|
7
|
+
to focus immediately on the feature that she wants to test.
|
8
|
+
|
9
|
+
### Motivation
|
10
|
+
|
11
|
+
It is often in many situations that we wonder how something works in a language or
|
12
|
+
library. One of the best ways to find out the answer in such scenarios is to create
|
13
|
+
a minimum piece of code that can test the specific case we have in mind. However,
|
14
|
+
creating such files may involve some overhead and the creation of boilerplate code
|
15
|
+
to allow the testing. This can cause people to give up creating the snippet and instead
|
16
|
+
just look up on the Internet, which can take more time and you likely will not learn
|
17
|
+
as much. The goal of this project is, therefore, reduce the cost of testing and
|
18
|
+
learning on your own.
|
19
|
+
|
20
|
+
### Example
|
21
|
+
|
22
|
+
`snp` is especially useful for quick tests that you want to perform in environments
|
23
|
+
in which a significant amount of boilerplate is involved. Suppose you frequently
|
24
|
+
test the expected effect of `jQuery` functions. You could create a snippet such as
|
25
|
+
|
26
|
+
~~~erb
|
27
|
+
<%# file: ~/.snp/jquery_test.js.erb %>
|
28
|
+
<html>
|
29
|
+
<head><title><%= title %></title></head>
|
30
|
+
|
31
|
+
<body>
|
32
|
+
|
33
|
+
<script src="http://code.jquery.com/jquery-<%= jquery_version %>.min.js"></script>
|
34
|
+
|
35
|
+
<script>
|
36
|
+
(function() {
|
37
|
+
// code goes here
|
38
|
+
})();
|
39
|
+
</script>
|
40
|
+
</body>
|
41
|
+
</html>
|
42
|
+
~~~
|
43
|
+
|
44
|
+
With that file set up once, whenever you want to perform a test of something related to
|
45
|
+
`jQuery` all you have to do is type:
|
46
|
+
|
47
|
+
~~~console
|
48
|
+
$ snp --title callbacks --jquery-version 2.1.1 jquery_test.js
|
49
|
+
~~~
|
50
|
+
|
51
|
+
Variable substitutions happen as you expect them to, and your favorite editor is fired up
|
52
|
+
with the snippet content, waiting for you to actually test what you wanted in the first place.
|
53
|
+
|
54
|
+
### Rules of the game
|
55
|
+
|
56
|
+
* Snippet templates are by default placed under the `~/.snp` directory. You can
|
57
|
+
override that by defining the `SNP_PATH` environment variable, which accepts a
|
58
|
+
list of directories in pretty much the same way that the shell's `PATH` does.
|
59
|
+
|
60
|
+
* All snippet templates are ERB files and must have a name with the according
|
61
|
+
`.erb` extension.
|
62
|
+
|
63
|
+
* You do not have fill in every piece of dynamic content in the command line when
|
64
|
+
creating a new snippet from a template. They can have defaults and you can define
|
65
|
+
them by placing a yaml file with the same name as the template with the default
|
66
|
+
contents of each dynamic piece of content in the template. Note that arguments
|
67
|
+
passed to the command line override those definitions.
|
68
|
+
|
69
|
+
Example: suppose you have the following snippet named `introduction.txt.erb`:
|
70
|
+
|
71
|
+
~~~erb
|
72
|
+
<%= greeting %>, my name is <%= name %>, and I'm from <%= country %>.
|
73
|
+
~~~
|
74
|
+
|
75
|
+
You can then create a `introduction.txt.yml` file to define the default values for
|
76
|
+
the dynamic variables in the snippet above:
|
77
|
+
|
78
|
+
~~~yaml
|
79
|
+
greeting: "Hello"
|
80
|
+
name: "Renato"
|
81
|
+
country: "Brazil"
|
82
|
+
~~~
|
83
|
+
|
84
|
+
Now you can create snippets from that template using the default values using just:
|
85
|
+
|
86
|
+
~~~console
|
87
|
+
$ snp introduction.txt
|
88
|
+
# => "Hello, my name is Renato, and I'm from Brazil."
|
89
|
+
~~~
|
90
|
+
|
91
|
+
You can override specific values when creating a new snippet as well:
|
92
|
+
|
93
|
+
~~~console
|
94
|
+
$ snp --name David --country UK
|
95
|
+
# => "Hello, my anme is David, and I'm from UK."
|
96
|
+
~~~
|
97
|
+
|
98
|
+
### Contributions/Bugs
|
99
|
+
|
100
|
+
Email me, or create an issue/pull request on the GitHub repository.
|
101
|
+
|
102
|
+
### License
|
103
|
+
|
104
|
+
MIT. See `MIT-LICENSE` file for details.
|
data/lib/snp.rb
ADDED
data/lib/snp/cli.rb
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'slop'
|
3
|
+
|
4
|
+
module Snp
|
5
|
+
# Snp::Printer
|
6
|
+
#
|
7
|
+
# This class is responsible for outputing string in normal output and error streams.
|
8
|
+
# It defaults to `STDOUT` and `STDERR`, respectively but can be used to generate output
|
9
|
+
# for other streams.
|
10
|
+
#
|
11
|
+
# Example
|
12
|
+
#
|
13
|
+
# stream = Snp::Printer.new
|
14
|
+
# stream.out('Hello') # => 'Hello' is written to the standard output
|
15
|
+
# stream.err('ERROR!') # => 'ERROR!' is written to the standard error
|
16
|
+
class Printer
|
17
|
+
def initialize(out = STDOUT, err = STDERR)
|
18
|
+
@out = out
|
19
|
+
@err = err
|
20
|
+
end
|
21
|
+
|
22
|
+
def out(message)
|
23
|
+
@out.puts message
|
24
|
+
end
|
25
|
+
|
26
|
+
def err(message)
|
27
|
+
@err.puts message
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Snp::InvalidOptions
|
32
|
+
#
|
33
|
+
# This exception is raised when there is an error parsing command line options
|
34
|
+
# passed to `snp`.
|
35
|
+
class InvalidOptions < StandardError
|
36
|
+
def initialize(invalid_option)
|
37
|
+
super("Invalid option: #{invalid_option}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Snp::CLI
|
42
|
+
#
|
43
|
+
# This class is responsible for parsing command line options passed to `snp` and
|
44
|
+
# retrieve the template name to be compiled and possibly options to override data
|
45
|
+
# for the template.
|
46
|
+
#
|
47
|
+
# Example
|
48
|
+
#
|
49
|
+
# CLI.parse_options # => ['/Users/john/.snp/jquery.html.erb', { version: '1.9' }]
|
50
|
+
class CLI
|
51
|
+
# Public: extract template name and other data that should be used to compile the
|
52
|
+
# template.
|
53
|
+
#
|
54
|
+
# arguments - an array of arguments that should be parsed. Defaults to `ARGV`.
|
55
|
+
#
|
56
|
+
# This method generates the snippet and fires your text editor in case it is set up,
|
57
|
+
# or prints the snippet to the standard output.
|
58
|
+
def self.run(arguments = ARGV.dup)
|
59
|
+
new(arguments).start
|
60
|
+
end
|
61
|
+
|
62
|
+
attr_reader :printer, :template_name
|
63
|
+
|
64
|
+
# Internal: creates a new `Snp::CLI` instance.
|
65
|
+
#
|
66
|
+
# params - array of arguments.
|
67
|
+
# printer - the printer object through which feedback messages are sent to.
|
68
|
+
# The passed object must respond to `out` and `err` for normal
|
69
|
+
# and error situations, respectively.
|
70
|
+
def initialize(params, printer = Printer.new)
|
71
|
+
@params = params
|
72
|
+
@options = {}
|
73
|
+
@printer = printer
|
74
|
+
end
|
75
|
+
|
76
|
+
# Internal: actually does the parsing job and compiles the snippet.
|
77
|
+
def start
|
78
|
+
@template_name, template_data = parse
|
79
|
+
|
80
|
+
snippet = Compiler.build(template_name, template_data)
|
81
|
+
|
82
|
+
edit(snippet) || printer.out(snippet)
|
83
|
+
rescue => exception
|
84
|
+
printer.err exception.message
|
85
|
+
help_and_exit
|
86
|
+
end
|
87
|
+
|
88
|
+
# Internal: parses command line options.
|
89
|
+
#
|
90
|
+
# Returns the template name and extra options to be used when compiling
|
91
|
+
# the snippet, extracted from command line arguments.
|
92
|
+
def parse
|
93
|
+
help_and_exit if no_options_passed?
|
94
|
+
|
95
|
+
template_name = parse_static_options
|
96
|
+
template_data = parse_dynamic_options
|
97
|
+
|
98
|
+
[template_name, template_data]
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# Internal: parses the command line options to check for static options
|
104
|
+
# (version number and help).
|
105
|
+
def parse_static_options
|
106
|
+
option_parser.parse!(@params)
|
107
|
+
@params.pop
|
108
|
+
end
|
109
|
+
|
110
|
+
# Internal: parses dynamic options, creating options according to the arguments
|
111
|
+
# passed on the command line.
|
112
|
+
#
|
113
|
+
# Example
|
114
|
+
#
|
115
|
+
# # command is '--project snp --language ruby template_name'
|
116
|
+
# parse_dynamic_options # => { 'project' => 'snp', 'language' => 'ruby' }
|
117
|
+
def parse_dynamic_options
|
118
|
+
if no_options_passed?
|
119
|
+
{}
|
120
|
+
else
|
121
|
+
dynamic_parser.parse!(@params)
|
122
|
+
|
123
|
+
data = dynamic_parser.to_hash
|
124
|
+
invalid_key = data.find { |key, value| value.nil? }
|
125
|
+
|
126
|
+
if invalid_key
|
127
|
+
raise InvalidOptions.new(invalid_key.first)
|
128
|
+
end
|
129
|
+
|
130
|
+
data
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Internal: builds the static option parser. Recognizes `-V` for version and `-h`
|
135
|
+
# for help.
|
136
|
+
def option_parser
|
137
|
+
@_option_parser ||= Slop.new do |command|
|
138
|
+
command.banner "Usage: #{program_name} [options] [template_name]"
|
139
|
+
|
140
|
+
command.on('-V', 'Shows version and exits') do
|
141
|
+
print_and_exit Snp::VERSION
|
142
|
+
end
|
143
|
+
|
144
|
+
command.on('-h', 'Shows this message') do
|
145
|
+
print_and_exit command.to_s
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Internal: builds the dynamic option parser, that creates options on the fly according
|
151
|
+
# to the passed command line options.
|
152
|
+
def dynamic_parser
|
153
|
+
@_dynamic_parser ||= Slop.new(autocreate: true)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Internal: prints a message and exits.
|
157
|
+
#
|
158
|
+
# message - the message to be printed before exiting.
|
159
|
+
#
|
160
|
+
# This method finishes the current process with a success exit status.
|
161
|
+
def print_and_exit(message)
|
162
|
+
printer.out message
|
163
|
+
exit
|
164
|
+
end
|
165
|
+
|
166
|
+
# Internal: returns the editor that should be used when editing a generated
|
167
|
+
# snippet. Looks for editor names in the `SNP_EDITOR` and `EDITOR` environment
|
168
|
+
# variables, respectively.
|
169
|
+
def editor
|
170
|
+
@_editor ||= ENV['SNP_EDITOR'] || ENV['EDITOR']
|
171
|
+
end
|
172
|
+
|
173
|
+
# Internal: Opens the preferred text editor with the content of a snippet.
|
174
|
+
#
|
175
|
+
# snippet - a string with the snippet content that should be edited.
|
176
|
+
def edit(snippet)
|
177
|
+
if editor && !editor.empty?
|
178
|
+
snippet_file = file_for(snippet)
|
179
|
+
Process.exec "#{editor} '#{snippet_file}'"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Internal: creates a file in the working directory to wihch the snippet
|
184
|
+
# contents will be written to, allowing it to be edited.
|
185
|
+
#
|
186
|
+
# content - the content of the final snippet.
|
187
|
+
def file_for(content)
|
188
|
+
"snp_#{template_name}".tap do |file_name|
|
189
|
+
File.open(file_name, "w+") { |f| f.write(content) }
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Internal: the program name to be used when generating output to the user.
|
194
|
+
def program_name
|
195
|
+
File.basename($0, '.*')
|
196
|
+
end
|
197
|
+
|
198
|
+
# Internal: prints help message and exits with a failure exit status.
|
199
|
+
def help_and_exit
|
200
|
+
printer.err help_message
|
201
|
+
exit 1
|
202
|
+
end
|
203
|
+
|
204
|
+
# Internal: returns the help message for the `snp` command.
|
205
|
+
def help_message
|
206
|
+
option_parser.to_s
|
207
|
+
end
|
208
|
+
|
209
|
+
# Internal: checks whether or not any arguments were passed on the command line.
|
210
|
+
def no_options_passed?
|
211
|
+
@params.empty?
|
212
|
+
end
|
213
|
+
|
214
|
+
# Internal: returns the extension of the template name, to be used in the
|
215
|
+
# generated snippet.
|
216
|
+
def template_extension
|
217
|
+
@_extension ||= begin
|
218
|
+
match_data = template_name.match(/.+(\..+)/)
|
219
|
+
|
220
|
+
# set it to the empty string in case there is no extension to allow for
|
221
|
+
# proper memoization of its value
|
222
|
+
match_data ? match_data[1] : ""
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
data/lib/snp/compiler.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Snp
|
4
|
+
# Snp::Compiler
|
5
|
+
#
|
6
|
+
# This class takes a template file name and builds it, using the template
|
7
|
+
# definition, default data to be used and extra options that override the
|
8
|
+
# default ones.
|
9
|
+
#
|
10
|
+
# Example
|
11
|
+
#
|
12
|
+
# Compiler.build('js.html', inline: true)
|
13
|
+
class Compiler
|
14
|
+
def self.build(template_name, extra_options)
|
15
|
+
new(template_name, extra_options).compile
|
16
|
+
end
|
17
|
+
|
18
|
+
# Public: creates a new Snp::Compiler instance.
|
19
|
+
#
|
20
|
+
# template - the template name.
|
21
|
+
# extra_options - options to override default data to build the template.
|
22
|
+
def initialize(template, extra_options)
|
23
|
+
@template = template
|
24
|
+
@options = extra_options
|
25
|
+
end
|
26
|
+
|
27
|
+
# Public: actually compiles the template.
|
28
|
+
#
|
29
|
+
# Returns a string with the compiled version of the snippet.
|
30
|
+
def compile
|
31
|
+
template.compile(compilation_context)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# Internal: builds the ERB context to be used to generate the snippet.
|
37
|
+
# Consists of the default for the template plus the extra options
|
38
|
+
# passed on initialization.
|
39
|
+
def compilation_context
|
40
|
+
TemplateContext.for(default_data.merge(@options))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Internal: searches the default data file for the template and parses it.
|
44
|
+
#
|
45
|
+
# Returns a hash with the default data if available, or an empty hash otherwise.
|
46
|
+
def default_data
|
47
|
+
Data.for(@template)
|
48
|
+
end
|
49
|
+
|
50
|
+
def template
|
51
|
+
Template.new(@template, path)
|
52
|
+
end
|
53
|
+
|
54
|
+
def path
|
55
|
+
@_path ||= Path.new
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/snp/data.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Snp
|
4
|
+
# Snp::Data
|
5
|
+
#
|
6
|
+
# This class is responsible for fetching the default data to be used when
|
7
|
+
# compiling a template. This defaults to the data available on a YAML file
|
8
|
+
# located in `SNP_PATH`, if available.
|
9
|
+
#
|
10
|
+
# Example
|
11
|
+
#
|
12
|
+
# # Given there is a jquery.yml file in `SNP_PATH`, then
|
13
|
+
# data = Snp::Data.for('jquery')
|
14
|
+
# # => { 'version' => '1.9', 'cdn' => true }
|
15
|
+
class Data
|
16
|
+
# Public: fetches the default data for the given template and parses it.
|
17
|
+
#
|
18
|
+
# template - the template name whose data is to be fetched.
|
19
|
+
#
|
20
|
+
# Returns a hash with the data.
|
21
|
+
def self.for(template)
|
22
|
+
new(template).to_hash
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public: creates a new `Snp::Data` instance for the template given.
|
26
|
+
def initialize(template, path = Path.new)
|
27
|
+
@template = template
|
28
|
+
@path = path
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: fetches the data file and parses it, if available.
|
32
|
+
#
|
33
|
+
# Returns a hash of the parsed data.
|
34
|
+
def to_hash
|
35
|
+
if absolute_path
|
36
|
+
YAML.load_file(absolute_path)
|
37
|
+
else
|
38
|
+
{}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Internal: returns the absolute path to the template file, searching for the
|
45
|
+
# directories in `SNP_PATH`.
|
46
|
+
def absolute_path
|
47
|
+
@path.which(@template, 'yml')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/snp/path.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Snp
|
2
|
+
# Snp::Path
|
3
|
+
#
|
4
|
+
# This class is intended to wrap the logic of finding the paths in which template
|
5
|
+
# and data files should be placed.
|
6
|
+
#
|
7
|
+
# Example
|
8
|
+
#
|
9
|
+
# Snp::Path.new.which('jquery') # => '/etc/snp/jquery.erb'
|
10
|
+
class Path
|
11
|
+
# Public: returns the list of absolute paths to the directories in which
|
12
|
+
# the templates should be looked.
|
13
|
+
def absolute_paths
|
14
|
+
dir_list.map { |d| File.expand_path(d) }
|
15
|
+
end
|
16
|
+
|
17
|
+
# Public: resolves a template file by looking in the template path.
|
18
|
+
#
|
19
|
+
# template - the template name.
|
20
|
+
# extension - the extension of the desired template.
|
21
|
+
#
|
22
|
+
# Returns a string with the full path of the template file, or nil if it is not
|
23
|
+
# found.
|
24
|
+
def which(template, extension)
|
25
|
+
template_with_extension = with_extension(template, extension)
|
26
|
+
|
27
|
+
path = absolute_paths.find do |path|
|
28
|
+
File.exists?(File.join(path, template_with_extension))
|
29
|
+
end
|
30
|
+
|
31
|
+
if path
|
32
|
+
File.join(path, template_with_extension)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# Internal: retrieves a list of paths that should be searched by looking the `SNP_PATH`
|
39
|
+
# environment variable or falling back to the default path.
|
40
|
+
def dir_list
|
41
|
+
path_from_env || default_path
|
42
|
+
end
|
43
|
+
|
44
|
+
# Internal: parses the SNP_PATH environment variable, if it is set. The format
|
45
|
+
# of this variable follows the same convention of the shell's PATH variable: a series
|
46
|
+
# of directories separated by a collon.
|
47
|
+
def path_from_env
|
48
|
+
ENV['SNP_PATH'] && ENV['SNP_PATH'].split(':')
|
49
|
+
end
|
50
|
+
|
51
|
+
# Internal: The default path to be used when the SNP_PATH environment variable
|
52
|
+
# is not set.
|
53
|
+
def default_path
|
54
|
+
['~/.snp']
|
55
|
+
end
|
56
|
+
|
57
|
+
# Internal: checks if the given name ends with the passed `extension`.
|
58
|
+
#
|
59
|
+
# template - the template file name.
|
60
|
+
def has_extension?(template, extension)
|
61
|
+
comparison_length = extension.size + 1 # account for the separator `.`
|
62
|
+
template[-comparison_length, comparison_length] == ".#{extension}"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Internal: appends a given extension to the template file name, unless it is
|
66
|
+
# already present.
|
67
|
+
#
|
68
|
+
# template - the template name.
|
69
|
+
# extension - the extension to be appended.
|
70
|
+
#
|
71
|
+
# Examples
|
72
|
+
#
|
73
|
+
# with_extension('template', 'erb') # => 'template.erb'
|
74
|
+
# with_extension('template.erb', 'erb') # => 'template.erb'
|
75
|
+
def with_extension(template, extension)
|
76
|
+
if has_extension?(template, extension)
|
77
|
+
template
|
78
|
+
else
|
79
|
+
[template, extension].join(".")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/snp/template.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Snp
|
4
|
+
# Snp::TemplateNotFound
|
5
|
+
#
|
6
|
+
# This exception is raised in case the template file passed is not found in any
|
7
|
+
# directory in snp path.
|
8
|
+
class TemplateNotFound < StandardError
|
9
|
+
def initialize(template_name, path)
|
10
|
+
super("Template #{template_name} was not found in #{path.inspect}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Snp::Template
|
15
|
+
#
|
16
|
+
# The Template class represents a snippet definition through an ERB template.
|
17
|
+
# Template files are looked in a series of directories that can be defined via
|
18
|
+
# the SNP_PATH environment variable. By default, these snippet definitions are
|
19
|
+
# searched in the `.snp` directory in your home directory.
|
20
|
+
#
|
21
|
+
# Examples
|
22
|
+
#
|
23
|
+
# t = Snp::Template.new('jquery.erb')
|
24
|
+
# t.compile(binding) # => '<html><head>...'
|
25
|
+
class Template
|
26
|
+
# Public: creates a new template instance.
|
27
|
+
#
|
28
|
+
# template_file - the basename of the template file.
|
29
|
+
def initialize(template_file, path = Path.new)
|
30
|
+
@file = template_file
|
31
|
+
@path = path
|
32
|
+
end
|
33
|
+
|
34
|
+
# Public: compiles the template content to an effective snippet, ready to use.
|
35
|
+
#
|
36
|
+
# context - a `Binding` object to be used as context in the template compilation.
|
37
|
+
#
|
38
|
+
# Returns a string with the compiled template.
|
39
|
+
def compile(context)
|
40
|
+
if template_content
|
41
|
+
ERB.new(template_content, 0, '-').result(context)
|
42
|
+
else
|
43
|
+
raise TemplateNotFound.new(@file, @path.absolute_paths)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Internal: returns a string with the content of the template file.
|
50
|
+
def template_content
|
51
|
+
if absolute_path
|
52
|
+
File.read(absolute_path)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Internal: returns the absolute path to the template, or `nil`, in case it is
|
57
|
+
# not found.
|
58
|
+
def absolute_path
|
59
|
+
@path.which(@file, 'erb')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Snp
|
2
|
+
# Snp::TemplateContext
|
3
|
+
#
|
4
|
+
# This class aims to represent the context in which a snippet template is
|
5
|
+
# compiled. It receives a hash of keys and values that act as properties to be
|
6
|
+
# used in the template. For example, if you have a template with the content:
|
7
|
+
#
|
8
|
+
# <html>
|
9
|
+
# <head><title><%= title %></title></head>
|
10
|
+
# </html>
|
11
|
+
#
|
12
|
+
# Then a proper context for this snippet compilation would be:
|
13
|
+
#
|
14
|
+
# TemplateContext.for(title: 'My beautiful page')
|
15
|
+
class TemplateContext
|
16
|
+
class InsufficientContext < StandardError
|
17
|
+
attr_reader :missing_property
|
18
|
+
|
19
|
+
def initialize(property)
|
20
|
+
@missing_property = property.to_s
|
21
|
+
super %(Insufficient context: no defined value for property "#{missing_property}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public: returns the binding for the passed `attributes`.
|
26
|
+
def self.for(attributes)
|
27
|
+
new(attributes).erb_binding
|
28
|
+
end
|
29
|
+
|
30
|
+
# Public: creates a new Snp::TemplateContext object.
|
31
|
+
#
|
32
|
+
# context - a hash of properties and values to be used in as context of the template.
|
33
|
+
#
|
34
|
+
# The hash is used so that the resulting object responds to each key in `context`,
|
35
|
+
# returning the accoring value.
|
36
|
+
def initialize(context)
|
37
|
+
@context = context
|
38
|
+
|
39
|
+
context.each do |property, value|
|
40
|
+
method_name = normalize(property)
|
41
|
+
define_property(method_name, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def erb_binding
|
46
|
+
binding
|
47
|
+
end
|
48
|
+
|
49
|
+
def respond_to_missing?(method, *)
|
50
|
+
@context.has_key?(normalize(method))
|
51
|
+
end
|
52
|
+
|
53
|
+
# In case an unknown method is called on the template context, we raise a proper
|
54
|
+
# exception that must be rescued and properly handled.
|
55
|
+
#
|
56
|
+
# Reaching this point means we need variables in the snippet that were not provided.
|
57
|
+
def method_missing(method, *)
|
58
|
+
raise InsufficientContext.new(method)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# Internal: returns a propperty name with underscores where dashes were present.
|
64
|
+
#
|
65
|
+
# name - the property name.
|
66
|
+
#
|
67
|
+
# Examples
|
68
|
+
#
|
69
|
+
# prepare('name') # => 'name'
|
70
|
+
# prepare('update-ref') # => 'update_ref'
|
71
|
+
def normalize(name)
|
72
|
+
name.to_s.gsub('-', '_')
|
73
|
+
end
|
74
|
+
|
75
|
+
# Internal: defines a method with `property` name, and returning `value`.
|
76
|
+
# If `value` is a boolean, this method will also define a predicate method.
|
77
|
+
def define_property(property, value)
|
78
|
+
define_singleton_method(property) { value }
|
79
|
+
|
80
|
+
if value == true || value == false
|
81
|
+
define_singleton_method("#{property}?") { value }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/snp/version.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'snp/cli'
|
3
|
+
|
4
|
+
describe Snp::CLI do
|
5
|
+
class TestPrinter
|
6
|
+
attr_reader :output, :error
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@output = ''
|
10
|
+
@error = ''
|
11
|
+
end
|
12
|
+
|
13
|
+
def out(message)
|
14
|
+
@output << message
|
15
|
+
end
|
16
|
+
|
17
|
+
def err(message)
|
18
|
+
@error << message
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '.parse_options' do
|
23
|
+
it 'delegates to #run' do
|
24
|
+
double = stub(start: 'double')
|
25
|
+
Snp::CLI.stubs(:new).returns(double)
|
26
|
+
|
27
|
+
Snp::CLI.run.must_equal 'double'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#parse' do
|
32
|
+
def no_exit(&block)
|
33
|
+
block.call
|
34
|
+
rescue SystemExit
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'prints help message when no arguments are passed' do
|
38
|
+
printer = TestPrinter.new
|
39
|
+
cli = Snp::CLI.new([], printer)
|
40
|
+
|
41
|
+
no_exit { cli.parse }
|
42
|
+
|
43
|
+
printer.output.wont_be_nil
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'can print version' do
|
47
|
+
printer = TestPrinter.new
|
48
|
+
cli = Snp::CLI.new(['-V'], printer)
|
49
|
+
|
50
|
+
no_exit { cli.parse }
|
51
|
+
|
52
|
+
printer.output.must_equal Snp::VERSION
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'can print help message' do
|
56
|
+
printer = TestPrinter.new
|
57
|
+
cli = Snp::CLI.new(['-h'], printer)
|
58
|
+
|
59
|
+
no_exit { cli.parse }
|
60
|
+
|
61
|
+
printer.output.wont_be_nil
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'retrieves the template name' do
|
65
|
+
cli = Snp::CLI.new(['snp'])
|
66
|
+
options = cli.parse
|
67
|
+
|
68
|
+
options.must_equal ['snp', {}]
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'fetches dynamic options' do
|
72
|
+
cli = Snp::CLI.new(['--type', 'gem', '--count', '3', 'snp'])
|
73
|
+
options = cli.parse
|
74
|
+
|
75
|
+
options.must_equal ['snp', { type: 'gem', count: '3' }]
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'throws an error if more than one template name is given' do
|
79
|
+
printer = TestPrinter.new
|
80
|
+
cli = Snp::CLI.new(['--count', '3', 'some_name', 'snp'], printer)
|
81
|
+
|
82
|
+
lambda {
|
83
|
+
no_exit { cli.parse }
|
84
|
+
}.must_raise(Snp::InvalidOptions)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#start' do
|
89
|
+
it 'writes the compiled version to its output stream' do
|
90
|
+
printer = TestPrinter.new
|
91
|
+
cli = Snp::CLI.new(['snp'], printer)
|
92
|
+
Snp::Compiler.stubs(:build).returns('compiled snippet')
|
93
|
+
|
94
|
+
cli.start
|
95
|
+
|
96
|
+
printer.output.must_equal 'compiled snippet'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Snp::Compiler do
|
4
|
+
describe '.build' do
|
5
|
+
it 'delegates to #compile' do
|
6
|
+
compiler = stub(compile: 'compiled snippet')
|
7
|
+
Snp::Compiler.stubs(:new).returns(compiler)
|
8
|
+
|
9
|
+
Snp::Compiler.build('snp', {}).must_equal 'compiled snippet'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#compile' do
|
14
|
+
def template_content
|
15
|
+
'<% if say_hello? %>' +
|
16
|
+
'Hello, <%= name %>' +
|
17
|
+
'<% else %>' +
|
18
|
+
'Farewell, <%= name %>' +
|
19
|
+
'<% end %>'
|
20
|
+
end
|
21
|
+
|
22
|
+
def default_options
|
23
|
+
{ say_hello: true, name: 'John' }
|
24
|
+
end
|
25
|
+
|
26
|
+
def stub_file_operations
|
27
|
+
File.stubs(:exists?).returns(true)
|
28
|
+
File.stubs(:read).returns(template_content)
|
29
|
+
YAML.stubs(:load_file).returns(default_options)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'generates compiled snippet when all options are available' do
|
33
|
+
stub_file_operations
|
34
|
+
Snp::Compiler.new('template_name', {}).compile.must_equal 'Hello, John'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'overrides default data with the ones passed' do
|
38
|
+
stub_file_operations
|
39
|
+
Snp::Compiler.new('template_name', name: 'Arthur').compile.must_equal 'Hello, Arthur'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Snp::Data do
|
4
|
+
describe '.for' do
|
5
|
+
it 'delegates to #to_hash' do
|
6
|
+
data = stub(to_hash: 'snp')
|
7
|
+
Snp::Data.stubs(:new).returns(data)
|
8
|
+
|
9
|
+
Snp::Data.for('anything').must_equal 'snp'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#to_hash' do
|
14
|
+
it 'is empty when no data file is found' do
|
15
|
+
File.stubs(:exists?).returns(false)
|
16
|
+
|
17
|
+
Snp::Data.new('snp').to_hash.must_equal({})
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'parses the content of the data file' do
|
21
|
+
data = { name: 'snp', language: 'ruby' }
|
22
|
+
path = File.expand_path('~/.snp/snp.yml')
|
23
|
+
|
24
|
+
File.stubs(:exists?).returns(true)
|
25
|
+
YAML.stubs(:load_file).with(path).returns(data)
|
26
|
+
|
27
|
+
Snp::Data.new('snp').to_hash.must_equal data
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Snp::Path do
|
4
|
+
describe '#absolute_paths' do
|
5
|
+
it 'defaults to the user home directory' do
|
6
|
+
Snp::Path.new.absolute_paths.must_equal Array(File.expand_path('~/.snp'))
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'uses the value in the `SNP_PATH` variable when available' do
|
10
|
+
ENV['SNP_PATH'] = '~/.snp:/etc/snp'
|
11
|
+
|
12
|
+
Snp::Path.new.absolute_paths.must_equal [File.expand_path('~/.snp'), '/etc/snp']
|
13
|
+
|
14
|
+
ENV['SNP_PATH'] = nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#which' do
|
19
|
+
def subject
|
20
|
+
Snp::Path.new
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'is nil in case there is no file in the path' do
|
24
|
+
File.stubs(:exists?).returns(false)
|
25
|
+
|
26
|
+
subject.which('template', 'erb').must_be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns the absolute path to the template appending the extension' do
|
30
|
+
File.stubs(:exists?).returns(true)
|
31
|
+
|
32
|
+
subject.which('snp', 'erb').must_equal File.expand_path('~/.snp/snp.erb')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'finds the snippet in case it has more than one extension' do
|
36
|
+
File.stubs(:exists?).returns(true)
|
37
|
+
|
38
|
+
subject.which('snp.erb.js', 'js').must_equal File.expand_path('~/.snp/snp.erb.js')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'does not append extension if it template already has it' do
|
42
|
+
File.stubs(:exists?).returns(true)
|
43
|
+
|
44
|
+
subject.which('snp.erb', 'erb').must_equal File.expand_path('~/.snp/snp.erb')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Snp::TemplateContext do
|
4
|
+
describe '.for' do
|
5
|
+
it 'delegates to #erb_binding' do
|
6
|
+
context = stub(erb_binding: 'binding')
|
7
|
+
Snp::TemplateContext.stubs(:new).returns(context)
|
8
|
+
|
9
|
+
Snp::TemplateContext.for('template_name').must_equal 'binding'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#erb_binding' do
|
14
|
+
it 'returns an instance of `Binding`' do
|
15
|
+
Snp::TemplateContext.new(key: 'value').erb_binding.must_be_instance_of Binding
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'responds to methods passed as hash' do
|
20
|
+
context = Snp::TemplateContext.new(greeting: 'Hello', name: 'snp')
|
21
|
+
context.greeting.must_equal 'Hello'
|
22
|
+
context.name.must_equal 'snp'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'generates predicate methods for boolean attributes' do
|
26
|
+
context = Snp::TemplateContext.new(awesome: true, sad: false)
|
27
|
+
context.awesome?.must_equal true
|
28
|
+
context.sad?.must_equal false
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'changes dash for underscore in generated methods' do
|
32
|
+
context = Snp::TemplateContext.new('is-awesome' => true)
|
33
|
+
context.is_awesome?.must_equal true
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'politely responds to methods named after context keys' do
|
37
|
+
context = Snp::TemplateContext.new(snp: 'snp')
|
38
|
+
context.must_respond_to(:snp)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'responds to method names in its normalized forms' do
|
42
|
+
context = Snp::TemplateContext.new(:"gem-name" => 'snp')
|
43
|
+
context.must_respond_to(:gem_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'raises proper error when called with non-existing property' do
|
47
|
+
context = Snp::TemplateContext.new(snp: 'snp')
|
48
|
+
lambda {
|
49
|
+
context.invalid_property
|
50
|
+
}.must_raise(Snp::TemplateContext::InsufficientContext)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Snp::Template do
|
4
|
+
describe '#compile' do
|
5
|
+
class ERBContext
|
6
|
+
def greeting
|
7
|
+
'Hello'
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
'snp'
|
12
|
+
end
|
13
|
+
|
14
|
+
def context
|
15
|
+
binding
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'generates a string with the processed template' do
|
20
|
+
template_content = '<%= greeting %> from <%= name %>'
|
21
|
+
File.stubs(:exists?).returns(true)
|
22
|
+
File.stubs(:read).returns(template_content)
|
23
|
+
|
24
|
+
template = Snp::Template.new('template.erb')
|
25
|
+
template.compile(ERBContext.new.context).must_equal 'Hello from snp'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'raises an error in case the template is not found' do
|
29
|
+
File.stubs(:exists?).returns(false)
|
30
|
+
template = Snp::Template.new('template.erb')
|
31
|
+
|
32
|
+
lambda {
|
33
|
+
template.compile({})
|
34
|
+
}.must_raise Snp::TemplateNotFound
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'minitest/mock'
|
4
|
+
require 'minitest/pride'
|
5
|
+
|
6
|
+
require 'mocha/setup'
|
7
|
+
|
8
|
+
require 'snp'
|
9
|
+
|
10
|
+
# unset any possibly set `SNP_PATH` variable
|
11
|
+
ENV.delete('SNP_PATH')
|
12
|
+
|
13
|
+
# unset editors by default
|
14
|
+
ENV.delete('SNP_EDITOR')
|
15
|
+
ENV.delete('EDITOR')
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: snp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Renato Mascarenhas
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: slop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mocha
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.1'
|
41
|
+
description: snp allows you to create snippets in an automated and reusable manner.
|
42
|
+
email: mascarenhas.renato@gmail.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- MIT-LICENSE
|
48
|
+
- README.md
|
49
|
+
- lib/snp.rb
|
50
|
+
- lib/snp/cli.rb
|
51
|
+
- lib/snp/compiler.rb
|
52
|
+
- lib/snp/data.rb
|
53
|
+
- lib/snp/path.rb
|
54
|
+
- lib/snp/template.rb
|
55
|
+
- lib/snp/template_context.rb
|
56
|
+
- lib/snp/version.rb
|
57
|
+
- test/snp/cli_test.rb
|
58
|
+
- test/snp/compiler_test.rb
|
59
|
+
- test/snp/data_test.rb
|
60
|
+
- test/snp/path_test.rb
|
61
|
+
- test/snp/template_context_test.rb
|
62
|
+
- test/snp/template_test.rb
|
63
|
+
- test/test_helper.rb
|
64
|
+
homepage: https://github.com/rmascarenhas/snp
|
65
|
+
licenses:
|
66
|
+
- MIT
|
67
|
+
metadata: {}
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project: snp
|
84
|
+
rubygems_version: 2.2.2
|
85
|
+
signing_key:
|
86
|
+
specification_version: 4
|
87
|
+
summary: Quickly and easily create code snippets.
|
88
|
+
test_files:
|
89
|
+
- test/snp/compiler_test.rb
|
90
|
+
- test/snp/data_test.rb
|
91
|
+
- test/snp/template_test.rb
|
92
|
+
- test/snp/cli_test.rb
|
93
|
+
- test/snp/template_context_test.rb
|
94
|
+
- test/snp/path_test.rb
|
95
|
+
- test/test_helper.rb
|