noe 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,3 +1,30 @@
1
+ # 1.1.0 / FIX ME
2
+
3
+ * Template specification/instantiation enhancements
4
+
5
+ * Introduced a manifest entry in template-info
6
+ * Introduced an auto detection of the wlang dialect to use based on file extensions.
7
+ The dialect may also be specified under template-info/manifest/a_file_name/wlang-dialect
8
+ entry
9
+ * All hashes found in .noespec variables are methodized before being passed to template
10
+ * Templates are now instantiated on a specification being the result of YAML merging
11
+ between the user's .noespec file and the template noespec.yaml file.
12
+
13
+ * Command enhancements
14
+
15
+ * Removed 'noe create', which is replaced by an extended version named 'noe prepare'
16
+ * 'noe go' now supports --interactive and --safe-override additional options to control conflict strategy
17
+ * Added a 'noe show-spec' command that shows the complete specification used by 'noe go'
18
+ See 'noe help show-spec' for details
19
+ * 'noe COMMAND --help' is now an alias for 'noe help COMMAND'
20
+ * A wlang backtrace is now displayed when an instantation error occurs on 'noe go'
21
+
22
+ * Other changes
23
+
24
+ * Bumped wlang version to 0.10.0 to gain inclusion features on wlang/ruby and wlang/yaml
25
+ * Ruby skeleton largely enhanced (see it's own CHANGELOG.md)
26
+ * Noe code is now managed by Noe itself
27
+
1
28
  # 1.0.0 / 2011-01-10
2
29
 
3
30
  * Enhancements
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'http://rubygems.org'
2
+ gemspec :name => "noe"
@@ -0,0 +1,22 @@
1
+ # Licence
2
+
3
+ Copyright (c) 2011 - Bernard Lambeau
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,23 +1,14 @@
1
1
  # Noe - A simple and extensible project generator
2
2
 
3
- Noe helps development by providing support for project templates and instantiation.
3
+ Noe is a tool that generates projects from predefined skeletons (aka project/application
4
+ templates). Skeletons are designed for building specific products (a ruby library, a static
5
+ or dynamic web site, ...). Noe instantiates them and helps you maintaining your product
6
+ via meta-information provided by a .noespec yaml file.
4
7
 
5
- ## Why?
6
-
7
- I'm pretty sure I have seen announcements for similar projects on ruby-lang in the past,
8
- but I could not find them anymore... so I started mine. Please let me know alternatives
9
- and I'll add them below:
10
-
11
- See also:
12
-
13
- * ...
14
-
15
- Other reasons:
16
-
17
- * Noe is agnostic: it does not make any assumption about project semantics
18
- * Noe does not restrict itself to generation of ruby projects
19
- * Noe is not required at runtime: once your project is generated you're done
20
- * I don't like magic
8
+ Noe comes bundled with a skeleton for creating and maintaining a ruby gem. This skeleton
9
+ is written and maintained to follow ruby best practices and may also be tuned for your own
10
+ needs. Read more about it and related projects as well as the underlying philosophy in the
11
+ sections below.
21
12
 
22
13
  ## Getting started
23
14
 
@@ -26,19 +17,11 @@ Other reasons:
26
17
  [noe help install]
27
18
  noe install
28
19
 
29
- Have a loot at ~/.noerc and ~/.noe for configuration and a default ruby
30
- template.
31
-
32
- ## Usage summary
20
+ Have a loot at ~/.noerc and ~/.noe for configuration and a default ruby template. To
21
+ instantiate a ruby project simply execute the following commands in turn:
33
22
 
34
- Maintain your templates under ~/.noe (or what you provided at installation time). Have a
35
- look at github to find xxx.noe projects to find well-designed/documented templates for
36
- specific needs.
37
-
38
- To create a fresh new project:
39
-
40
- # Given a template xxx under ~/.noe/xxx
41
- noe create --template=xxx foo
23
+ # Given a template ruby under ~/.noe/ruby, install by default
24
+ noe prepare --template=ruby foo
42
25
  cd foo
43
26
 
44
27
  # Edit the template configuration foo/foo.noespec
@@ -47,10 +30,92 @@ To create a fresh new project:
47
30
  # Launch template instantiation
48
31
  noe go
49
32
 
50
- That's it! But also have a look at 'noe help create' and 'not help go' for additional
33
+ That's it! But also have a look at 'noe help prepare' and 'not help go' for additional
51
34
  options.
52
35
 
53
- ## About templates
36
+ ## Philosophy
37
+
38
+ Noe is designed to follow a certain number of good principles and helps you following
39
+ them as well.
40
+
41
+ ### Separation of concerns
42
+
43
+ Noe maintains a strong separation of concerns. In particular one has to make the distinction
44
+ between a) Noe itself, b) a skeleton and c) an instantiated product. This fact has two
45
+ main consequences:
46
+
47
+ * Noe itself **is not dedicated to specific products** (like a ruby library). Even if Noe
48
+ comes bundled with a default skeleton for ruby projects, writing skeletons for something
49
+ else should not be a problem. In other words, Noe itself is agnostic: the semantics of
50
+ generated products is the secret of the skeleton, under the responsibility of it's
51
+ maintainer.
52
+
53
+ * Noe **should not be a runtime dependency** of the product. Good skeletons maintain this
54
+ separation. As an example the default ruby skeleton is strictly independent of Noe itself.
55
+ Principles discussed below explain why this is important.
56
+
57
+ ### Master the tools YOU use
58
+
59
+ The separation of concerns described previously also drives what you have to learn and what
60
+ tools you have to master:
61
+
62
+ * As an ordinary Noe user (vs. skeleton maintainer) and because Noe itself (unlike skeletons
63
+ is project agnostic, you only have to know **basic Noe commands** (see 'noe --help') and
64
+ should never have to study Noe's API and internals. In contrast, you have to **master the
65
+ tools and best practices of your product's ecosystem**. A good skeleton should help you
66
+ along this task. As an example, the default ruby skeleton is fully documented to help you
67
+ gaining understanding of ***rake*, *spec*, *yard*, *bundler*** and so on but **not noe
68
+ itself**.
69
+
70
+ * This explains why Noe itself is not a runtime dependency. Using a particular skeleton
71
+ already means learning a lot, at least in the long run (see the section about Magic below).
72
+ Noe avoids interfering with generated products to avoid making the learning curve even
73
+ worse.
74
+
75
+ * Being a skeleton creator/maintainer is another story of course. To write a skeleton you'll
76
+ also have to learn **Noe's API and internals**. To write a good/reusable one, you'll
77
+ certainly have to **master the full ecosystem and best practices of the targetted product**,
78
+ which is a good opportunity for learning and sharing it!
79
+
80
+ ### Magic Only If Flexible
81
+
82
+ "Don't Repeat Yourself" and "Convention over Configuration" are certainly good principles.
83
+ However tuning, configuration and options exist, are useful and should certainly not be
84
+ hidden to the user. Instead configuration and options should come with default values,
85
+ and should be fully documented. Providing magic is great if there is a user-centric way
86
+ (in contrast to a developer one) of understanding and controlling the magic and underlying
87
+ assumptions.
88
+
89
+ As an example, the default ruby template comes with some magic: you can create a project
90
+ and immediately invoke 'rake test', 'rake yard', ... and not investigating further. You
91
+ can also have a look at the _tasks_ folder to understand and control the rake tasks that
92
+ your project will use... In fact, you **must** investigate: the generated product is yours,
93
+ not mine and YOU have to master your build chain!
94
+
95
+ ## Ruby skeleton and Related projects
96
+
97
+ Noe is inspired by existing projects, mostly from the ruby community. In particular, the
98
+ default ruby template has been heavily influenced by the projects below as well as feedback
99
+ of their authors:
100
+
101
+ * [hoe](http://seattlerb.rubyforge.org/hoe/), Ryan Davis and Eric Hodel
102
+ * [echoe](https://github.com/fauna/echoe), Evan Weaver
103
+ * [bones](https://github.com/TwP/bones), Tim Pease
104
+
105
+ These projects help you generating and maintaining ruby projects (generally gem libraries,
106
+ in fact). All provide powerful tools that supports you along the different steps of your
107
+ ruby software lifecycle (creating, testing, releasing, announcing, and so on.). They mostly
108
+ differ in the way you can tune/configure the generated project for specific needs.
109
+
110
+ These projects differ from the Ruby skeleton proposed by Noe in that they use a control
111
+ approach (rake tasks installed in your project via a development/runtime dependency) while
112
+ Noe uses a generative approach (the generated ruby project and rake tasks do not depend on
113
+ Noe at all).
114
+
115
+ You'll find more information about the Noe's ruby skeleton in it's own
116
+ [README](https://github.com/blambeau/noe/blob/master/templates/ruby/README.md).
117
+
118
+ ## Short guide for template maintainers
54
119
 
55
120
  Under ~/.noe, a valid template folder (say xxx) has the following structure
56
121
 
@@ -63,16 +128,17 @@ Under ~/.noe, a valid template folder (say xxx) has the following structure
63
128
 
64
129
  ### noespec.yaml
65
130
 
66
- The noespec.yaml file of a template is used to formally describe the template. When a project
67
- (say foo) is created (see 'noe create') using a template (say ruby) the file
68
- ~/.noe/ruby/noespec.yaml is used to generate foo/foo.noespec. The later is then used by
69
- 'noe go' to instantiate the project.
131
+ The noespec.yaml file of a template is used to formally describe the template. When a
132
+ project (say foo) is created (see 'noe prepare') using a template (say ruby) the file
133
+ ~/.noe/ruby/noespec.yaml is used to generate foo/foo.noespec. The later is then used
134
+ by 'noe go' to instantiate the project.
70
135
 
71
136
  The noespec.yaml file should ressemble something like this:
72
137
 
73
138
  # DO NOT TOUCH 'name' entry and specify the other
74
139
  template-info:
75
140
  name: !{template_name}
141
+ summary: ...
76
142
  description: ...
77
143
  version: ...
78
144
  author: ...
@@ -90,16 +156,16 @@ Have a look at ~/.noe/ruby/noespec.yaml and ~/.noe/ruby/src for an example.
90
156
 
91
157
  ### Instantiation process
92
158
 
93
- The instantiation process is really simple. Given the variables described in the noespec.yaml
94
- file (for which values are specified in your .noespec file) templates can use the following
95
- meta-constructions:
159
+ The instantiation process is really simple. Given the variables described in the
160
+ noespec.yaml file (for which values are specified in your .noespec file) templates
161
+ can use the following meta-constructions:
96
162
 
97
- * Template files and directories containing `__variable__` in their name are automatically
163
+ * Template files and directories containing `__variable__` in their name are automatically
98
164
  renamed (`__variable__` is replaced by the corresponding value).
99
- * All template files are instantiated by [wlang](https://github.com/blambeau/wlang). You don't
100
- have to know wlang in depth. You simply have to know that `!{ruby_expression}` in a file is
101
- replaced by the expression evaluation. Variables are automatically in scope of such expressions,
102
- so that `!{variable}` is replaced by its value.
165
+ * All template files are instantiated by [wlang](https://github.com/blambeau/wlang). You
166
+ don't have to know wlang in depth. You simply have to know that `!{ruby_expression}` in
167
+ a file is replaced by the expression evaluation. Variables are automatically in scope
168
+ of such expressions, so that `!{variable}` is replaced by its value.
103
169
 
104
170
  ## Contributing
105
171
 
@@ -111,7 +177,7 @@ Fork Noe on github! I'm particularly interested in the following enhancements:
111
177
  * Add support for multi-generated files from arrays in .noespec files
112
178
  * ...
113
179
 
114
- If you think that your template is worth considering for (ruby, rails, js, latex, or anything
115
- else) please let me known and I'll add it to the list below.
180
+ If you think that your template is worth considering for (ruby, rails, js, latex, or
181
+ anything else) please let me known and I'll add it to the list below.
116
182
 
117
183
  * ...
data/Rakefile CHANGED
@@ -1,24 +1,22 @@
1
- require "rake/gempackagetask"
2
- require "rspec/core/rake_task"
3
- require "yard"
4
-
5
- # We run tests by default
6
- task :default => :spec
7
-
8
- desc "Run all examples"
9
- RSpec::Core::RakeTask.new(:spec) do |t|
10
- t.rspec_opts = %w[--color]
11
- t.verbose = false
1
+ begin
2
+ gem "bundler", "~> 1.0"
3
+ require "bundler/setup"
4
+ rescue LoadError
5
+ abort "This project requires bundler, try 'gem install bundler'"
12
6
  end
13
7
 
14
- # About yard documentation
15
- YARD::Rake::YardocTask.new do |t|
16
- t.files = ['lib/**/*.rb']
17
- t.options = ['--output-dir', 'doc/api', '-', "README.md", "CHANGELOG.md"]
18
- end
8
+ # Dynamically load the gem spec
9
+ $gemspec_file = File.expand_path('../noe.gemspec', __FILE__)
10
+ $gemspec = Kernel.eval(File.read($gemspec_file))
11
+
12
+ # We run tests by default
13
+ task :default => :test
19
14
 
20
- desc "Create the .gem package"
21
- $spec = Kernel.eval(File.read(File.expand_path('../noe.gemspec', __FILE__)))
22
- Rake::GemPackageTask.new($spec) do |pkg|
23
- pkg.need_tar = true
15
+ #
16
+ # Install all tasks found in tasks folder
17
+ #
18
+ # See .rake files there for complete documentation.
19
+ #
20
+ Dir["tasks/*.rake"].each do |taskfile|
21
+ instance_eval File.read(taskfile), taskfile
24
22
  end
data/bin/noe CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env ruby -rubygems
2
2
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
3
  require 'noe'
4
4
  Noe::Main.run(ARGV)
data/lib/noe.rb CHANGED
@@ -1,39 +1,25 @@
1
1
  module Noe
2
2
 
3
3
  # Noe's version
4
- VERSION = "1.0.0".freeze
5
-
6
- # Requires some gem
7
- def self.require(gem_name, version = nil, retried = false)
8
- begin
9
- Kernel.require gem_name
10
- rescue LoadError
11
- if retried
12
- raise
13
- else
14
- retried = true
15
- require 'rubygems'
16
- gem gem_name, version
17
- retry
18
- end
19
- end
20
- end
4
+ VERSION = "1.1.0".freeze
21
5
 
22
6
  class Error < StandardError; end
23
7
 
24
8
  end # module Noe
25
-
26
- Noe.require('quickl', ">= 0.2.0")
27
- Noe.require('wlang', ">= 0.9")
9
+ require 'noe/loader'
28
10
  require 'yaml'
29
11
  require 'fileutils'
12
+ require 'noe/ext/array'
13
+ require 'noe/ext/hash'
30
14
  require 'noe/config'
31
15
  require 'noe/template'
16
+
32
17
  require 'noe/main'
33
18
  require 'noe/commons'
34
19
  require 'noe/install'
35
20
  require 'noe/help'
36
21
  require 'noe/list'
37
- require 'noe/create'
22
+ require 'noe/prepare'
38
23
  require 'noe/go'
24
+ require 'noe/show_spec'
39
25
 
@@ -1,6 +1,16 @@
1
1
  module Noe
2
2
  module Commons
3
3
 
4
+ # Install options
5
+ def self.add_common_options(opt)
6
+ opt.on_tail("--version", "Show version") do
7
+ raise Quickl::Exit, "#{File.basename($0 || 'noe')} #{Noe::VERSION} (c) 2011, Bernard Lambeau"
8
+ end
9
+ opt.on_tail('--help', "Show detailed help") do
10
+ raise Quickl::Help
11
+ end
12
+ end
13
+
4
14
  # Returns configuration to use
5
15
  def config
6
16
  requester.config
@@ -13,6 +23,19 @@ module Noe
13
23
  def template(name = config.default)
14
24
  Template.new(File.join(templates_dir, name))
15
25
  end
26
+
27
+ def find_noespec_file(args)
28
+ # Find spec file
29
+ spec_file = if args.size == 1
30
+ valid_read_file!(args.first)
31
+ else
32
+ spec_files = Dir['*.noespec']
33
+ if spec_files.size > 1
34
+ raise Noe::Error, "Ambiguous request, multiple specs: #{spec_files.join(', ')}"
35
+ end
36
+ spec_files.first
37
+ end
38
+ end
16
39
 
17
40
  end # module Commons
18
41
  end # module Noe
@@ -22,8 +22,8 @@ templates-dir:
22
22
 
23
23
  #
24
24
  # Name of the default template that you want to use. Commands
25
- # that need a template (see 'noe help create', for example) use this
26
- # by default, and allow overriding this via a --template=NAME option.
25
+ # that need a template (see 'noe help prepare', for example) use this
26
+ # by default, and allow overriding it via a --template=NAME option.
27
27
  #
28
28
  default:
29
29
  ruby
@@ -0,0 +1,18 @@
1
+ class Array
2
+
3
+ def methodize_hashes!(recursive = true)
4
+ self.each do |val|
5
+ case val
6
+ when Hash
7
+ val.methodize!(recursive)
8
+ when Array
9
+ val.methodize_hashes!(recursive)
10
+ end
11
+ end
12
+ end
13
+
14
+ def noe_merge(right)
15
+ (self + right).uniq
16
+ end
17
+
18
+ end # class Array
@@ -0,0 +1,48 @@
1
+ class Hash
2
+
3
+ # Methodize this hash
4
+ def methodize!(recursive = true)
5
+ self.extend(Methodize)
6
+ if recursive
7
+ self.values.each do |val|
8
+ case val
9
+ when Hash
10
+ val.methodize!(recursive)
11
+ when Array
12
+ val.methodize_hashes!(recursive)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ # Makes a fully recursive merge
19
+ def noe_merge(right)
20
+ self.merge(right) do |key,oldval,newval|
21
+ if oldval.nil?
22
+ newval
23
+ elsif oldval.class != newval.class
24
+ raise Noe::Error, "Conflict on #{key} has to be resolved manually, sorry.\n"\
25
+ "#{oldval} (#{oldval.class}) vs. #{newval} (#{newval.class})"
26
+ elsif oldval.respond_to?(:noe_merge)
27
+ oldval.noe_merge(newval)
28
+ else
29
+ newval
30
+ end
31
+ end
32
+ end
33
+
34
+ module Methodize
35
+
36
+ # Allows using hash.key as a synonym for hash[:key] and
37
+ # hash['key']
38
+ def method_missing(name, *args, &block)
39
+ if args.empty? and block.nil?
40
+ self[name] || self[name.to_s]
41
+ else
42
+ super(name, *args, &block)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ end