snp 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|