noe 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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
@@ -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
@@ -0,0 +1,8 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ describe Noe do
3
+
4
+ it "should have a version number" do
5
+ Noe.const_defined?(:VERSION).should be_true
6
+ end
7
+
8
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'rubygems'
3
+ require 'rspec'
4
+ require 'noe'
@@ -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