noe 1.0.0 → 1.1.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.
Files changed (49) hide show
  1. data/CHANGELOG.md +27 -0
  2. data/Gemfile +2 -0
  3. data/LICENCE.md +22 -0
  4. data/README.md +111 -45
  5. data/Rakefile +18 -20
  6. data/bin/noe +1 -1
  7. data/lib/noe.rb +7 -21
  8. data/lib/noe/commons.rb +23 -0
  9. data/lib/noe/config.yaml +2 -2
  10. data/lib/noe/ext/array.rb +18 -0
  11. data/lib/noe/ext/hash.rb +48 -0
  12. data/lib/noe/go.rb +158 -40
  13. data/lib/noe/install.rb +13 -7
  14. data/lib/noe/list.rb +34 -10
  15. data/lib/noe/loader.rb +67 -0
  16. data/lib/noe/main.rb +15 -15
  17. data/lib/noe/prepare.rb +121 -0
  18. data/lib/noe/show_spec.rb +45 -0
  19. data/lib/noe/template.rb +84 -4
  20. data/noe.gemspec +186 -30
  21. data/spec/ext/hash/methodize_spec.rb +30 -0
  22. data/spec/noe_spec.rb +4 -0
  23. data/spec/spec_helper.rb +0 -2
  24. data/spec/template/entry/infer_wlang_dialect_spec.rb +31 -0
  25. data/tasks/gem.rake +44 -0
  26. data/tasks/spec_test.rake +61 -0
  27. data/tasks/unit_test.rake +56 -0
  28. data/tasks/yard.rake +36 -0
  29. data/templates/ruby/CHANGELOG.md +9 -1
  30. data/templates/ruby/README.md +47 -10
  31. data/templates/ruby/noespec.yaml +195 -26
  32. data/templates/ruby/short.yaml +33 -0
  33. data/templates/ruby/src/Gemfile +2 -0
  34. data/templates/ruby/src/LICENCE.md +22 -0
  35. data/templates/ruby/src/Manifest.txt +11 -0
  36. data/templates/ruby/src/README.md +6 -1
  37. data/templates/ruby/src/Rakefile +16 -36
  38. data/templates/ruby/src/__lower__.gemspec +178 -23
  39. data/templates/ruby/src/lib/__lower__.rb +5 -2
  40. data/templates/ruby/src/lib/__lower__/loader.rb +65 -0
  41. data/templates/ruby/src/spec/spec_helper.rb +0 -2
  42. data/templates/ruby/src/tasks/gem.rake +44 -0
  43. data/templates/ruby/src/tasks/spec_test.rake +61 -0
  44. data/templates/ruby/src/tasks/unit_test.rake +56 -0
  45. data/templates/ruby/src/tasks/yard.rake +36 -0
  46. metadata +349 -79
  47. data/LICENCE.txt +0 -20
  48. data/lib/noe/create.rb +0 -77
  49. data/templates/ruby/src/LICENCE.txt +0 -20
@@ -12,8 +12,11 @@ module Noe
12
12
  # #{summarized_subcommands}
13
13
  #
14
14
  # DESCRIPTION
15
- # Noe helps development via support for well-designed templates. See
16
- # https://github.com/blambeau/noe for more information.
15
+ # Noe is a tool that generates projects from predefined skeletons (aka project
16
+ # templates). Skeletons are designed for building specific products (a ruby
17
+ # library, a static or dynamic web site, ...). Noe instantiates them and helps
18
+ # you maintaining your product via meta-information provided by a .noespec yaml
19
+ # file. See https://github.com/blambeau/noe for more information.
17
20
  #
18
21
  # See '#{program_name} help COMMAND' for more information on a specific command.
19
22
  #
@@ -27,8 +30,10 @@ module Noe
27
30
 
28
31
  # Returns Noe's configuration, loading it if required
29
32
  def config
30
- @config_file ||= find_config_file
31
- Config.new(@config_file)
33
+ @config ||= begin
34
+ @config_file ||= find_config_file
35
+ Config.new(@config_file)
36
+ end
32
37
  end
33
38
 
34
39
  # Finds the configuration file and loads automatically
@@ -49,22 +54,17 @@ module Noe
49
54
  "Show backtrace on error") do
50
55
  @backtrace = true
51
56
  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
57
+ Commons.add_common_options(opt)
62
58
  end
63
59
 
64
60
  # Runs the command
65
61
  def run(argv, requester = nil)
66
62
  super
67
- rescue Quickl::Error
63
+ rescue WLang::Error => ex
64
+ puts "#{ex.class}: #{ex.message}"
65
+ back = ex.wlang_backtrace || ex.backtrace
66
+ puts back.join("\n")
67
+ rescue Quickl::Error => ex
68
68
  raise
69
69
  rescue Noe::Error => ex
70
70
  puts "#{ex.class}: #{ex.message}"
@@ -0,0 +1,121 @@
1
+ require 'fileutils'
2
+ module Noe
3
+ class Main
4
+ #
5
+ # Prepare the generation of a new project
6
+ #
7
+ # SYNOPSIS
8
+ # #{program_name} #{command_name} [options] [PROJECT_NAME]
9
+ #
10
+ # OPTIONS
11
+ # #{summarized_options}
12
+ #
13
+ # DESCRIPTION
14
+ # This command prepares the generation of a fresh new project according to
15
+ # its first argument:
16
+ #
17
+ # - With a project name given as first argument, a new folder is created and
18
+ # a .noespec file is generated in it for the selected template (see below).
19
+ #
20
+ # - Without project name, Noe assumes that you want the current folder to
21
+ # be upgraded to follow the template conventions. In that case, a fresh
22
+ # new .noespec file is simply generated in the current folder.
23
+ #
24
+ # The template specified in ~/.noerc under :default is used by default.
25
+ # Use --template=xxx to override this.
26
+ #
27
+ # After creation, you'll have to edit the generated .noespec file then run
28
+ # 'noe go'.
29
+ #
30
+ # TYPICAL USAGE
31
+ #
32
+ # To create a fresh new project for a given template (ruby here), play the
33
+ # following scenario:
34
+ #
35
+ # # start creation of a fresh new ruby project
36
+ # noe prepare [--template=ruby] [--layout=short] foo
37
+ # cd foo
38
+ #
39
+ # # edit the configuration
40
+ # edit foo.noespec
41
+ #
42
+ # # launch template generation
43
+ # noe go
44
+ #
45
+ # To upgrade an existing project to follow a template (ruby here), the following
46
+ # scenario is worth considering:
47
+ #
48
+ # # generate a .noespec file in the current folder (let assume 'foo')
49
+ # noe prepare [--template=ruby] [--layout=short]
50
+ #
51
+ # # edit the configuration
52
+ # edit foo.noespec
53
+ #
54
+ # # launch template generation in interactive mode
55
+ # noe go --interactive
56
+ #
57
+ class Prepare < Quickl::Command(__FILE__, __LINE__)
58
+ include Noe::Commons
59
+
60
+ # Force mode?
61
+ attr_reader :force
62
+
63
+ # Install options
64
+ options do |opt|
65
+ opt.on('--template=TEMPLATE_NAME',
66
+ "Set the template to use (try 'noe list' to see what exists)") do |name|
67
+ config.default = name
68
+ end
69
+ @layout = "noespec"
70
+ opt.on('--layout=LAYOUT',
71
+ "Set the specification layout to use (idem)") do |l|
72
+ @layout = l
73
+ end
74
+ @force = false
75
+ opt.on('--force', '-f',
76
+ "Force overriding of existing .noespec file"){
77
+ @force = true
78
+ }
79
+ Commons.add_common_options(opt)
80
+ end
81
+
82
+ def generate_noespec_file(where)
83
+ if File.exists?(where) and not(force)
84
+ raise Noe::Error, "File #{where} already exists, remove it first or set --force."
85
+ else
86
+ tpl = template
87
+ File.open(where, 'w') do |out|
88
+ context = {'template_name' => tpl.name}
89
+ out << WLang::file_instantiate(tpl.spec_layout_file(@layout), context, "wlang/active-text")
90
+ end
91
+ end
92
+ where
93
+ end
94
+
95
+ def execute(args)
96
+ pname, where = nil, nil
97
+ case args.size
98
+ when 0
99
+ pname = File.basename(File.expand_path('.'))
100
+ where = generate_noespec_file("#{pname}.noespec")
101
+ when 1
102
+ pname = args.first
103
+ FileUtils.mkdir(pname) unless File.exists?(pname)
104
+ where = generate_noespec_file(File.join(pname, "#{pname}.noespec"))
105
+ else
106
+ raise Quickl::Help unless args.size > 1
107
+ end
108
+
109
+ # what's next
110
+ puts "Project successfully started !"
111
+ puts
112
+ puts "What's next?"
113
+ puts " * edit #{where}"
114
+ puts " * noe go"
115
+ puts
116
+ puts "Thank you for using Noe (v#{Noe::VERSION}), enjoy!"
117
+ end
118
+
119
+ end # class Create
120
+ end # class Main
121
+ end # module Noe
@@ -0,0 +1,45 @@
1
+ module Noe
2
+ class Main
3
+ #
4
+ # Show the actual noe specification that would be used by 'noe go'
5
+ #
6
+ # SYNOPSIS
7
+ # #{program_name} #{command_name} [SPEC_FILE]
8
+ #
9
+ # OPTIONS
10
+ # #{summarized_options}
11
+ #
12
+ # DESCRIPTION
13
+ # This command merges the .noespec file given as first parameter (or found in
14
+ # the current folder) with the noespec.yaml file of the template and prints
15
+ # the result on the standard output.
16
+ #
17
+ # When 'noe go' is invoked, the actual specification it works with is the
18
+ # merging of what you specify in your .noespec file with default values
19
+ # provided by the template specification itself. In other words, your .noespec
20
+ # file simply overrides the default values provided in the template itself.
21
+ #
22
+ # Therefore, you can always keep your .noespec files simple by not specifying
23
+ # entries for which the default value is ok. However, making so could lead you
24
+ # to forget about some template options and this command is useful is such
25
+ # situations.
26
+ #
27
+ class ShowSpec < Quickl::Command(__FILE__, __LINE__)
28
+ include Noe::Commons
29
+
30
+ options do |opt|
31
+ Commons.add_common_options(opt)
32
+ end
33
+
34
+ def execute(args)
35
+ raise Quickl::Help if args.size > 1
36
+ spec_file = find_noespec_file(args)
37
+ spec = YAML::load(File.read(spec_file))
38
+ template = template(spec['template-info']['name'])
39
+ template.merge_spec(spec)
40
+ puts template.to_yaml
41
+ end
42
+
43
+ end # class ShowSpec
44
+ end # class Main
45
+ end # module Noe
@@ -23,9 +23,30 @@ module Noe
23
23
  end
24
24
  end
25
25
 
26
- # Returns path to the spec file
27
- def spec_file
28
- File.join(folder, "noespec.yaml")
26
+ def spec_layout_file(layout = 'noespec')
27
+ file = File.join(folder, "#{layout}.yaml")
28
+ if File.exists?(file)
29
+ file
30
+ else
31
+ puts "On #{file}"
32
+ raise Noe::Error, "Unknown specification layout: #{layout}, try 'noe list'"
33
+ end
34
+ end
35
+ alias :spec_file :spec_layout_file
36
+
37
+ # Returns an array with available layout names
38
+ def layouts
39
+ Dir[File.join(folder, '*.yaml')].collect{|f| File.basename(f, '.yaml')}
40
+ end
41
+
42
+ # Merges another spec file inside this template
43
+ def merge_spec_file(file)
44
+ merge_spec YAML::load(File.read(spec_file))
45
+ end
46
+
47
+ # Merges template spec with another spec given from a Hash
48
+ def merge_spec(hash)
49
+ @spec = @spec.noe_merge(hash)
29
50
  end
30
51
 
31
52
  # Returns template name
@@ -33,6 +54,11 @@ module Noe
33
54
  File.basename(folder)
34
55
  end
35
56
 
57
+ # Returns template summary
58
+ def summary
59
+ spec['template-info']['summary'] || description
60
+ end
61
+
36
62
  # Returns template description
37
63
  def description
38
64
  spec['template-info']['description']
@@ -43,6 +69,15 @@ module Noe
43
69
  spec['template-info']['version']
44
70
  end
45
71
 
72
+ # Returns the template variables entry
73
+ def variables
74
+ spec['variables']
75
+ end
76
+
77
+ def main_wlang_dialect
78
+ spec['template-info']['main-wlang-dialect']
79
+ end
80
+
46
81
  # Returns path to the sources folder
47
82
  def src_folder
48
83
  File.join(folder, "src")
@@ -58,6 +93,15 @@ module Noe
58
93
  Entry.new(self, paths.join(File::PATH_SEPARATOR))
59
94
  end
60
95
 
96
+ # Returns manifest Hash for a given entry
97
+ def manifest_for(entry)
98
+ manifest = spec['template-info']['manifest'] || {}
99
+ manifest[entry.path] || {
100
+ 'description' => "No description for #{entry.path}",
101
+ 'safe-override' => false
102
+ }
103
+ end
104
+
61
105
  # Visit the template
62
106
  def visit(entry = src_folder, &block)
63
107
  if entry.is_a?(Entry)
@@ -76,6 +120,11 @@ module Noe
76
120
  end
77
121
  alias :each :visit
78
122
 
123
+ # Delegated to spec
124
+ def to_yaml(*args)
125
+ spec.to_yaml(*args)
126
+ end
127
+
79
128
  private :__load
80
129
 
81
130
  # Entry inside a template structure
@@ -104,7 +153,7 @@ module Noe
104
153
  end
105
154
 
106
155
  # Relocate the path according to variables
107
- def relocate(variables)
156
+ def relocate(variables = template.variables)
108
157
  path.split(File::PATH_SEPARATOR).
109
158
  collect{|v| rename_one(variables, v)}.
110
159
  join(File::PATH_SEPARATOR)
@@ -137,6 +186,37 @@ module Noe
137
186
  def child_entry(name)
138
187
  template.entry(path.nil? ? name : File.join(path, name))
139
188
  end
189
+
190
+ # Returns the hash with the manifest for this entry
191
+ def manifest
192
+ template.manifest_for(self)
193
+ end
194
+
195
+ # Returns wlang dialect to use
196
+ def wlang_dialect
197
+ @wlang_dialect ||= begin
198
+ default = template.main_wlang_dialect
199
+ manifest['wlang-dialect'] || self.class.infer_wlang_dialect(relocate, default)
200
+ end
201
+ end
202
+
203
+ # Infers the wlang dialect to use for the entry
204
+ def self.infer_wlang_dialect(uri, default = nil)
205
+ res = case d = WLang::infer_dialect(uri)
206
+ when nil
207
+ nil
208
+ when /^wlang/
209
+ d
210
+ else
211
+ WLang::dialect("wlang/#{d}").qualified_name
212
+ end
213
+ res ? res : (default || 'wlang/active-text')
214
+ end
215
+
216
+ # Is this entry safe to override
217
+ def safe_override?
218
+ manifest['safe-override']
219
+ end
140
220
 
141
221
  end # class Entry
142
222
 
@@ -1,36 +1,192 @@
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')
1
+ # We require your library, mainly to have access to the VERSION number.
2
+ # Feel free to set $version manually.
3
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
4
+ require "noe"
5
+ $version = Noe::VERSION.dup
6
6
 
7
- s.author = %q{Bernard Lambeau}
8
- s.email = %q{blambeau@gmail.com}
7
+ #
8
+ # This is your Gem specification. Default values are provided so that your library
9
+ # should be correctly packaged given what you have described in the .noespec file.
10
+ #
11
+ Gem::Specification.new do |s|
12
+
13
+ ################################################################### ABOUT YOUR GEM
14
+
15
+ # Gem name (required)
16
+ s.name = "noe"
17
+
18
+ # Gem version (required)
19
+ s.version = $version
20
+
21
+ # A short summary of this gem
22
+ #
23
+ # This is displayed in `gem list -d`.
24
+ s.summary = "Noe is a tool that generates projects from predefined skeletons (aka project/application templates). Skeletons are designed for building specific products (a ruby library, a static or dynamic web site, ...). Noe instantiates them and helps you maintaining your product via meta-information provided by a .noespec yaml file."
9
25
 
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.}
26
+ # A long description of this gem (required)
27
+ #
28
+ # The description should be more detailed than the summary. For example,
29
+ # you might wish to copy the entire README into the description.
30
+ s.description = File.read(File.expand_path('../README.md', __FILE__))
31
+
32
+ # The URL of this gem home page (optional)
33
+ s.homepage = "http://github.com/blambeau/noe"
12
34
 
35
+ # Gem publication date (required but auto)
36
+ #
37
+ # Today is automatically used by default, uncomment only if
38
+ # you know what you do!
39
+ #
40
+ # s.date = Time.now.strftime('%Y-%m-%d')
41
+
42
+ # The license(s) for the library. Each license must be a short name, no
43
+ # more than 64 characters.
44
+ #
45
+ # s.licences = %w{}
46
+
47
+ # The rubyforge project this gem lives under (optional)
48
+ #
49
+ # s.rubyforge_project = nil
50
+
51
+ ################################################################### ABOUT THE AUTHORS
52
+
53
+ # The list of author names who wrote this gem.
54
+ #
55
+ # If you are providing multiple authors and multiple emails they should be
56
+ # in the same order.
57
+ #
58
+ s.authors = ["Bernard Lambeau"]
59
+
60
+ # Contact emails for this gem
61
+ #
62
+ # If you are providing multiple authors and multiple emails they should be
63
+ # in the same order.
64
+ #
65
+ # NOTE: Somewhat strangly this attribute is always singular!
66
+ # Don't replace by s.emails = ...
67
+ s.email = ["blambeau@gmail.com"]
68
+
69
+ ################################################################### PATHS, FILES, BINARIES
70
+
71
+ # Paths in the gem to add to $LOAD_PATH when this gem is
72
+ # activated (required).
73
+ #
74
+ # The default 'lib' is typically sufficient.
13
75
  s.require_paths = ["lib"]
76
+
77
+ # Files included in this gem.
78
+ #
79
+ # By default, we take all files included in the Manifest.txt file on root
80
+ # of the project. Entries of the manifest are interpreted as Dir[...]
81
+ # patterns so that lazy people may use wilcards like lib/**/*
82
+ #
83
+ here = File.dirname(__FILE__)
84
+ s.files = File.readlines(File.join(here, 'Manifest.txt')).
85
+ inject([]){|files, pattern|
86
+ files + Dir[File.join(here, pattern.strip)]
87
+ }
88
+
89
+ # Test files included in this gem.
90
+ #
91
+ s.test_files = Dir["test/**/*"] + Dir["spec/**/*"]
92
+
93
+ # The path in the gem for executable scripts (optional)
94
+ #
14
95
  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
96
 
97
+ # Executables included in the gem.
98
+ #
99
+ s.executables = (Dir["bin/*"]).collect{|f| File.basename(f)}
100
+
101
+ ################################################################### REQUIREMENTS & INSTALL
102
+ # Remember the gem version requirements operators and schemes:
103
+ # = Equals version
104
+ # != Not equal to version
105
+ # > Greater than version
106
+ # < Less than version
107
+ # >= Greater than or equal to
108
+ # <= Less than or equal to
109
+ # ~> Approximately greater than
110
+ #
111
+ # Don't forget to have a look at http://lmgtfy.com/?q=Ruby+Versioning+Policies
112
+ # for setting your gem version.
113
+ #
114
+ # For your requirements to other gems, remember that
115
+ # ">= 2.2.0" (optimistic: specify minimal version)
116
+ # ">= 2.2.0", "< 3.0" (pessimistic: not greater than the next major)
117
+ # "~> 2.2" (shortcut for ">= 2.2.0", "< 3.0")
118
+ # "~> 2.2.0" (shortcut for ">= 2.2.0", "< 2.3.0")
119
+ #
120
+
121
+ #
122
+ # One call to add_dependency('gem_name', 'gem version requirement') for each
123
+ # runtime dependency. These gems will be installed with your gem.
124
+ # One call to add_development_dependency('gem_name', 'gem version requirement')
125
+ # for each development dependency. These gems are required for developers
126
+ #
127
+ s.add_development_dependency("rake", "~> 0.8.7")
128
+ s.add_development_dependency("bundler", "~> 1.0")
129
+ s.add_development_dependency("rspec", "~> 2.4.0")
130
+ s.add_development_dependency("yard", "~> 0.6.4")
131
+ s.add_development_dependency("bluecloth", "~> 2.0.9")
132
+ s.add_dependency("wlang", "~> 0.10.0")
133
+ s.add_dependency("quickl", "~> 0.2.0")
134
+ s.add_dependency("highline", "~> 1.6.0")
135
+
136
+ # The version of ruby required by this gem
137
+ #
138
+ # Uncomment and set this if your gem requires specific ruby versions.
139
+ #
140
+ # s.required_ruby_version = ">= 0"
141
+
142
+ # The RubyGems version required by this gem
143
+ #
144
+ # s.required_rubygems_version = ">= 0"
145
+
146
+ # The platform this gem runs on. See Gem::Platform for details.
147
+ #
148
+ # s.platform = nil
149
+
150
+ # Extensions to build when installing the gem.
151
+ #
152
+ # Valid types of extensions are extconf.rb files, configure scripts
153
+ # and rakefiles or mkrf_conf files.
154
+ #
155
+ s.extensions = []
156
+
157
+ # External (to RubyGems) requirements that must be met for this gem to work.
158
+ # It’s simply information for the user.
159
+ #
160
+ s.requirements = nil
161
+
162
+ # A message that gets displayed after the gem is installed
163
+ #
164
+ # Uncomment and set this if you want to say something to the user
165
+ # after gem installation
166
+ #
167
+ s.post_install_message = "Noe successfully installed!\n\nWhat's next?\n - 'noe help install' for configuration and default templates\n - 'noe prepare --template=ruby hello_world'\n\nThank you for using Noe, enjoy!\n"
168
+
169
+ ################################################################### SECURITY
170
+
171
+ # The key used to sign this gem. See Gem::Security for details.
172
+ #
173
+ # s.signing_key = nil
174
+
175
+ # The certificate chain used to sign this gem. See Gem::Security for
176
+ # details.
177
+ #
178
+ # s.cert_chain = []
179
+
180
+ ################################################################### RDOC
181
+
182
+ # An ARGV style array of options to RDoc
183
+ #
184
+ # See 'rdoc --help' about this
185
+ #
186
+ s.rdoc_options = []
187
+
188
+ # Extra files to add to RDoc such as README
189
+ #
190
+ s.extra_rdoc_files = Dir["README.md"] + Dir["CHANGELOG.md"] + Dir["LICENCE.md"]
191
+
192
+ end