noe 1.0.0
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.
- data/CHANGELOG.md +5 -0
- data/LICENCE.txt +20 -0
- data/README.md +117 -0
- data/Rakefile +24 -0
- data/bin/noe +5 -0
- data/lib/noe.rb +39 -0
- data/lib/noe/commons.rb +18 -0
- data/lib/noe/config.rb +60 -0
- data/lib/noe/config.yaml +29 -0
- data/lib/noe/create.rb +77 -0
- data/lib/noe/go.rb +194 -0
- data/lib/noe/help.rb +26 -0
- data/lib/noe/install.rb +89 -0
- data/lib/noe/list.rb +39 -0
- data/lib/noe/main.rb +79 -0
- data/lib/noe/template.rb +144 -0
- data/noe.gemspec +36 -0
- data/spec/noe_spec.rb +8 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/template/entry/relocate_spec.rb +41 -0
- data/spec/template/entry/rename_one_spec.rb +31 -0
- data/templates/ruby/CHANGELOG.md +3 -0
- data/templates/ruby/README.md +24 -0
- data/templates/ruby/noespec.yaml +32 -0
- data/templates/ruby/src/CHANGELOG.md +5 -0
- data/templates/ruby/src/LICENCE.txt +20 -0
- data/templates/ruby/src/README.md +3 -0
- data/templates/ruby/src/Rakefile +42 -0
- data/templates/ruby/src/__lower__.gemspec +31 -0
- data/templates/ruby/src/lib/__lower__.rb +6 -0
- data/templates/ruby/src/spec/__lower___spec.rb +8 -0
- data/templates/ruby/src/spec/spec_helper.rb +4 -0
- metadata +183 -0
data/lib/noe/help.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Noe
|
2
|
+
class Main
|
3
|
+
#
|
4
|
+
# Show help about a specific command
|
5
|
+
#
|
6
|
+
# SYNOPSIS
|
7
|
+
# #{program_name} #{command_name} COMMAND
|
8
|
+
#
|
9
|
+
class Help < Quickl::Command(__FILE__, __LINE__)
|
10
|
+
|
11
|
+
# Let NoSuchCommandError be passed to higher stage
|
12
|
+
no_react_to Quickl::NoSuchCommand
|
13
|
+
|
14
|
+
# Command execution
|
15
|
+
def execute(args)
|
16
|
+
if args.size != 1
|
17
|
+
puts super_command.help
|
18
|
+
else
|
19
|
+
cmd = has_command!(args.first, super_command)
|
20
|
+
puts cmd.help
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end # class Help
|
25
|
+
end # class Main
|
26
|
+
end # module Noe
|
data/lib/noe/install.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
module Noe
|
3
|
+
class Main
|
4
|
+
#
|
5
|
+
# Install default configuration and template.
|
6
|
+
#
|
7
|
+
# SYNOPSIS
|
8
|
+
# #{program_name} #{command_name} [--force] [FOLDER]
|
9
|
+
#
|
10
|
+
# OPTIONS
|
11
|
+
# #{summarized_options}
|
12
|
+
#
|
13
|
+
# DESCRIPTION
|
14
|
+
# This command will install Noe's default configuration under
|
15
|
+
# FOLDER/.noerc and a default ruby template under FOLDER/.noe.
|
16
|
+
# Unless stated otherwise, FOLDER is user's home.
|
17
|
+
#
|
18
|
+
# If FOLDER/.noerc already exists, the comand safely fails.
|
19
|
+
# Use --force to override existing configuration.
|
20
|
+
#
|
21
|
+
class Install < Quickl::Command(__FILE__, __LINE__)
|
22
|
+
include Noe::Commons
|
23
|
+
|
24
|
+
# Force mode ?
|
25
|
+
attr_reader :force
|
26
|
+
|
27
|
+
# Install options
|
28
|
+
options do |opt|
|
29
|
+
@force = false
|
30
|
+
opt.on('--force', '-f',
|
31
|
+
"Force overriding on all existing files"){
|
32
|
+
@force = true
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute(args)
|
37
|
+
if args.size > 1
|
38
|
+
raise Quickl::InvalidArgument, "Needless arguments: #{args[1..-1].join(' ')}"
|
39
|
+
end
|
40
|
+
folder = args.first || ENV['HOME']
|
41
|
+
|
42
|
+
noerc_file = File.join(folder, '.noerc')
|
43
|
+
noe_folder = File.join(folder, '.noe')
|
44
|
+
|
45
|
+
# generate .noerc
|
46
|
+
if File.exists?(noerc_file) and not(force)
|
47
|
+
raise Noe::Error, "#{noerc_file} already exists, use --force to override"
|
48
|
+
end
|
49
|
+
File.open(noerc_file, 'w') do |out|
|
50
|
+
def_config = File.join(File.dirname(__FILE__), 'config.yaml')
|
51
|
+
context = { :templates_dir => noe_folder}
|
52
|
+
out << WLang::file_instantiate(def_config, context, 'wlang/active-string')
|
53
|
+
end
|
54
|
+
|
55
|
+
# generate .noe folder
|
56
|
+
unless File.exists?(noe_folder)
|
57
|
+
FileUtils.mkdir(noe_folder)
|
58
|
+
end
|
59
|
+
|
60
|
+
# copy default templates
|
61
|
+
tdir = File.expand_path('../../../templates', __FILE__)
|
62
|
+
Dir[File.join(tdir, '*')].each do |tpl|
|
63
|
+
target = File.join(noe_folder, File.basename(tpl))
|
64
|
+
if File.exists?(target)
|
65
|
+
if force
|
66
|
+
FileUtils.rm_rf target
|
67
|
+
else
|
68
|
+
puts "#{target} already exists, use --force to override"
|
69
|
+
next
|
70
|
+
end
|
71
|
+
end
|
72
|
+
FileUtils.cp_r tpl, noe_folder
|
73
|
+
end
|
74
|
+
|
75
|
+
# say something!
|
76
|
+
puts "Noe successfully installed !"
|
77
|
+
puts
|
78
|
+
puts "What's next?"
|
79
|
+
puts " * cat #{noerc_file}"
|
80
|
+
puts " * ls -lA #{noe_folder}"
|
81
|
+
puts " * noe list"
|
82
|
+
puts " * noe create hello_world"
|
83
|
+
puts
|
84
|
+
puts "Thank you for using Noe (v#{Noe::VERSION}), enjoy!"
|
85
|
+
end
|
86
|
+
|
87
|
+
end # class Install
|
88
|
+
end # class Main
|
89
|
+
end # module Noe
|
data/lib/noe/list.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Noe
|
2
|
+
class Main
|
3
|
+
#
|
4
|
+
# List available templates.
|
5
|
+
#
|
6
|
+
# SYNOPSIS
|
7
|
+
# #{program_name} #{command_name}
|
8
|
+
#
|
9
|
+
# DESCRIPTION
|
10
|
+
# This command list project templates found in the templates folder.
|
11
|
+
# The later is checked as a side effect.
|
12
|
+
#
|
13
|
+
# TIP
|
14
|
+
# Run this command to know where templates are located!
|
15
|
+
#
|
16
|
+
class List < Quickl::Command(__FILE__, __LINE__)
|
17
|
+
include Noe::Commons
|
18
|
+
|
19
|
+
def execute(args)
|
20
|
+
unless args.empty?
|
21
|
+
raise Quickl::InvalidArgument, "Needless argument: #{args.join(', ')}"
|
22
|
+
end
|
23
|
+
|
24
|
+
puts "Templates located in: #{templates_dir}"
|
25
|
+
Dir[File.join(templates_dir, '**')].collect do |tpl_dir|
|
26
|
+
begin
|
27
|
+
tpl = Template.new(tpl_dir)
|
28
|
+
puts " * %-#{25}s %s" % [ "#{tpl.name} (v#{tpl.version})" , tpl.description ]
|
29
|
+
tpl
|
30
|
+
rescue => ex
|
31
|
+
puts " * %-#{25}s %s" % [File.basename(tpl_dir), ex.message]
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end # class List
|
38
|
+
end # class Main
|
39
|
+
end # module Noe
|
data/lib/noe/main.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
module Noe
|
2
|
+
#
|
3
|
+
# Noe - A simple and extensible project generator
|
4
|
+
#
|
5
|
+
# SYNOPSIS
|
6
|
+
# #{program_name} [--version] [--help] COMMAND [cmd opts] ARGS...
|
7
|
+
#
|
8
|
+
# OPTIONS
|
9
|
+
# #{summarized_options}
|
10
|
+
#
|
11
|
+
# COMMANDS
|
12
|
+
# #{summarized_subcommands}
|
13
|
+
#
|
14
|
+
# DESCRIPTION
|
15
|
+
# Noe helps development via support for well-designed templates. See
|
16
|
+
# https://github.com/blambeau/noe for more information.
|
17
|
+
#
|
18
|
+
# See '#{program_name} help COMMAND' for more information on a specific command.
|
19
|
+
#
|
20
|
+
class Main < Quickl::Delegate(__FILE__, __LINE__)
|
21
|
+
|
22
|
+
# Configuration instance
|
23
|
+
attr_reader :config_file
|
24
|
+
|
25
|
+
# Show backtrace on error?
|
26
|
+
attr_reader :backtrace
|
27
|
+
|
28
|
+
# Returns Noe's configuration, loading it if required
|
29
|
+
def config
|
30
|
+
@config_file ||= find_config_file
|
31
|
+
Config.new(@config_file)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Finds the configuration file and loads automatically
|
35
|
+
def find_config_file
|
36
|
+
in_home = File.join(ENV['HOME'], '.noerc')
|
37
|
+
File.file?(in_home) ? in_home : nil
|
38
|
+
end
|
39
|
+
|
40
|
+
# Install options
|
41
|
+
options do |opt|
|
42
|
+
# Set a specific configuration file to use
|
43
|
+
opt.on('--config=FILE',
|
44
|
+
'Use a specific config file (defaults to ~/.noerc)') do |f|
|
45
|
+
@config_file = valid_read_file!(f)
|
46
|
+
end
|
47
|
+
# Show backtrace on error
|
48
|
+
opt.on_tail("--backtrace",
|
49
|
+
"Show backtrace on error") do
|
50
|
+
@backtrace = true
|
51
|
+
end
|
52
|
+
# Show the help and exit
|
53
|
+
opt.on_tail("--help",
|
54
|
+
"Show help") do
|
55
|
+
raise Quickl::Help
|
56
|
+
end
|
57
|
+
# Show version and exit
|
58
|
+
opt.on_tail("--version",
|
59
|
+
"Show version") do
|
60
|
+
raise Quickl::Exit, "#{program_name} #{Noe::VERSION} (c) 2011, Bernard Lambeau"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Runs the command
|
65
|
+
def run(argv, requester = nil)
|
66
|
+
super
|
67
|
+
rescue Quickl::Error
|
68
|
+
raise
|
69
|
+
rescue Noe::Error => ex
|
70
|
+
puts "#{ex.class}: #{ex.message}"
|
71
|
+
puts ex.backtrace.join("\n") if backtrace
|
72
|
+
rescue StandardError => ex
|
73
|
+
puts "Oups, Noe encountered a serious problem! Please report if a bug."
|
74
|
+
puts "#{ex.class}: #{ex.message}"
|
75
|
+
puts ex.backtrace.join("\n")
|
76
|
+
end
|
77
|
+
|
78
|
+
end # class Main
|
79
|
+
end # module Noe
|
data/lib/noe/template.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
module Noe
|
2
|
+
class Template
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
# Main folder of the template
|
6
|
+
attr_reader :folder
|
7
|
+
|
8
|
+
# Loaded specification
|
9
|
+
attr_reader :spec
|
10
|
+
|
11
|
+
# Creates a template instance
|
12
|
+
def initialize(folder)
|
13
|
+
@folder = folder
|
14
|
+
__load
|
15
|
+
end
|
16
|
+
|
17
|
+
# Loads the template from its folder
|
18
|
+
def __load
|
19
|
+
if File.file?(spec_file) and File.readable?(spec_file)
|
20
|
+
@spec = YAML::load(File.read(spec_file))
|
21
|
+
else
|
22
|
+
raise Noe::Error, "Unable to find template: #{spec_file}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns path to the spec file
|
27
|
+
def spec_file
|
28
|
+
File.join(folder, "noespec.yaml")
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns template name
|
32
|
+
def name
|
33
|
+
File.basename(folder)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns template description
|
37
|
+
def description
|
38
|
+
spec['template-info']['description']
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns template version
|
42
|
+
def version
|
43
|
+
spec['template-info']['version']
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns path to the sources folder
|
47
|
+
def src_folder
|
48
|
+
File.join(folder, "src")
|
49
|
+
end
|
50
|
+
|
51
|
+
# Ignore some file?
|
52
|
+
def ignore?(file)
|
53
|
+
['.', '..'].include? File.basename(file)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns an entry for a given relative path
|
57
|
+
def entry(*paths)
|
58
|
+
Entry.new(self, paths.join(File::PATH_SEPARATOR))
|
59
|
+
end
|
60
|
+
|
61
|
+
# Visit the template
|
62
|
+
def visit(entry = src_folder, &block)
|
63
|
+
if entry.is_a?(Entry)
|
64
|
+
block.call(entry)
|
65
|
+
else
|
66
|
+
entry = Entry.new(self, nil)
|
67
|
+
end
|
68
|
+
if entry.directory?
|
69
|
+
Dir.foreach(entry.realpath) do |child|
|
70
|
+
childentry = entry.child_entry(child)
|
71
|
+
unless ignore?(childentry.realpath)
|
72
|
+
visit(childentry, &block)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
alias :each :visit
|
78
|
+
|
79
|
+
private :__load
|
80
|
+
|
81
|
+
# Entry inside a template structure
|
82
|
+
class Entry
|
83
|
+
|
84
|
+
# Template where this entry is located
|
85
|
+
attr_reader :template
|
86
|
+
|
87
|
+
# Relative path of the entry inside the template
|
88
|
+
attr_reader :path
|
89
|
+
|
90
|
+
# Creates an entry instance
|
91
|
+
def initialize(template, path)
|
92
|
+
@template = template
|
93
|
+
@path = path
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns real absolute path of the entry
|
97
|
+
def realpath
|
98
|
+
path.nil? ? template.src_folder : File.join(template.src_folder, path)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns entry name
|
102
|
+
def name
|
103
|
+
File.basename(realpath)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Relocate the path according to variables
|
107
|
+
def relocate(variables)
|
108
|
+
path.split(File::PATH_SEPARATOR).
|
109
|
+
collect{|v| rename_one(variables, v)}.
|
110
|
+
join(File::PATH_SEPARATOR)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the target name, according to some variables
|
114
|
+
def rename_one(variables, name = self.name)
|
115
|
+
if name =~ /__([a-z]+)__/
|
116
|
+
if x = variables[$1]
|
117
|
+
name.gsub(/__([a-z]+)__/, x)
|
118
|
+
else
|
119
|
+
raise Noe::Error, "Missing variable #{$1}"
|
120
|
+
end
|
121
|
+
else
|
122
|
+
name
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Is the entry a file?
|
127
|
+
def file?
|
128
|
+
File.file?(realpath)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Is the entry a directory?
|
132
|
+
def directory?
|
133
|
+
File.directory?(realpath)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Builds an child entry for a given name
|
137
|
+
def child_entry(name)
|
138
|
+
template.entry(path.nil? ? name : File.join(path, name))
|
139
|
+
end
|
140
|
+
|
141
|
+
end # class Entry
|
142
|
+
|
143
|
+
end # class Template
|
144
|
+
end # module Noe
|
data/noe.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path('../lib/noe', __FILE__)
|
2
|
+
spec = Gem::Specification.new do |s|
|
3
|
+
s.name = %q{noe}
|
4
|
+
s.version = Noe::VERSION.dup
|
5
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
6
|
+
|
7
|
+
s.author = %q{Bernard Lambeau}
|
8
|
+
s.email = %q{blambeau@gmail.com}
|
9
|
+
|
10
|
+
s.description = %q{A simple and extensible project generator}
|
11
|
+
s.summary = %q{Noe helps development by providing support for project templates and instantiation.}
|
12
|
+
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
s.bindir = "bin"
|
15
|
+
s.executables = ["noe"]
|
16
|
+
|
17
|
+
s.extra_rdoc_files = ["README.md", "CHANGELOG.md"]
|
18
|
+
|
19
|
+
s.files =
|
20
|
+
Dir['bin/**/*'] +
|
21
|
+
Dir['lib/**/*'] +
|
22
|
+
Dir['spec/**/*'] +
|
23
|
+
Dir['templates/**/*'] +
|
24
|
+
%w{ noe.gemspec Rakefile README.md CHANGELOG.md LICENCE.txt}
|
25
|
+
|
26
|
+
s.add_dependency('wlang', '>= 0.9.2')
|
27
|
+
s.add_dependency('quickl', '>= 0.2.0')
|
28
|
+
|
29
|
+
s.add_development_dependency('rake')
|
30
|
+
s.add_development_dependency('rspec', ">= 2.4.0")
|
31
|
+
s.add_development_dependency('yard', ">= 0.6.4")
|
32
|
+
s.add_development_dependency('bluecloth', ">= 0.6.4")
|
33
|
+
|
34
|
+
s.homepage = %q{http://github.com/blambeau/noe}
|
35
|
+
end
|
36
|
+
|
data/spec/noe_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
2
|
+
module Noe
|
3
|
+
describe "Template::Entry#relocate" do
|
4
|
+
|
5
|
+
let(:template){
|
6
|
+
Template.new(File.expand_path('../../../../templates/ruby', __FILE__))
|
7
|
+
}
|
8
|
+
let(:vars){
|
9
|
+
{"lower" => "project"}
|
10
|
+
}
|
11
|
+
subject{
|
12
|
+
entry.relocate(vars)
|
13
|
+
}
|
14
|
+
|
15
|
+
describe "when nothing has to change" do
|
16
|
+
let(:entry){ template.entry('.gitignore') }
|
17
|
+
it{ should == ".gitignore" }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "when exactly a replacement" do
|
21
|
+
let(:entry){ template.entry("__lower__") }
|
22
|
+
it { should == "project" }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "when a replacement inside something else" do
|
26
|
+
let(:entry){ template.entry("__lower___spec.rb") }
|
27
|
+
it { should == "project_spec.rb" }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "when no replace and sub file" do
|
31
|
+
let(:entry){ template.entry("lib", "README.md") }
|
32
|
+
it { should == ["lib", "README.md"].join(File::PATH_SEPARATOR) }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "when no replace and sub file with replacement" do
|
36
|
+
let(:entry){ template.entry("lib", "__lower__.rb") }
|
37
|
+
it { should == ["lib", "project.rb"].join(File::PATH_SEPARATOR) }
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end # module Noe
|