basis 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,5 @@
1
+ require "autotest/restart"
2
+
3
+ Autotest.add_hook :initialize do |at|
4
+ at.testlib = "minitest/autorun"
5
+ end
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ === 1.0.0 / 2010-07-21
2
+
3
+ * Birthday!
data/Manifest.txt CHANGED
@@ -1,23 +1,14 @@
1
- History.txt
1
+ .autotest
2
+ CHANGELOG.rdoc
2
3
  Manifest.txt
3
- README.txt
4
+ README.rdoc
4
5
  Rakefile
5
6
  bin/basis
6
- lib/basis/engine.rb
7
- lib/basis/errors.rb
8
- lib/basis/options.rb
9
- lib/basis/templates.rb
10
- lib/basis/templates/base.rb
11
- lib/basis/templates/git.rb
12
- lib/basis/templates/list.rb
13
- lib/basis/templates/local.rb
14
- lib/basis/templates/state.rb
15
- lib/basis/version.rb
16
- lib/templates.yml
17
- test/basis/engine_test.rb
18
- test/basis/options_test.rb
19
- test/basis/templates/base_test.rb
20
- test/basis/templates_test.rb
21
- test/fixtures/local/erb/erb.txt.erb
22
- test/fixtures/local/project.name/project.name.txt
23
- test/helper.rb
7
+ lib/basis.rb
8
+ lib/basis/context.rb
9
+ lib/basis/my.rb
10
+ lib/basis/repo.rb
11
+ lib/basis/template.rb
12
+ test/test_basis_context.rb
13
+ test/test_basis_my.rb
14
+ test/test_basis_template.rb
data/README.rdoc ADDED
@@ -0,0 +1,41 @@
1
+ = Basis
2
+
3
+ * http://github.com/jbarnette/basis
4
+
5
+ == Description
6
+
7
+ Basis is a project skeleton generator.
8
+
9
+ It'll have more docs at some point.
10
+
11
+ == Examples
12
+
13
+ FIX (code sample of usage)
14
+
15
+ == Installation
16
+
17
+ $ gem install basis
18
+ $ basis --help
19
+
20
+ == License
21
+
22
+ Copyright 2010 John Barnette (code@jbarnette.com)
23
+
24
+ Permission is hereby granted, free of charge, to any person obtaining
25
+ a copy of this software and associated documentation files (the
26
+ 'Software'), to deal in the Software without restriction, including
27
+ without limitation the rights to use, copy, modify, merge, publish,
28
+ distribute, sublicense, and/or sell copies of the Software, and to
29
+ permit persons to whom the Software is furnished to do so, subject to
30
+ the following conditions:
31
+
32
+ The above copyright notice and this permission notice shall be
33
+ included in all copies or substantial portions of the Software.
34
+
35
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
36
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
38
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
39
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
40
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
41
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,8 +1,14 @@
1
- require "rubygems"
2
1
  require "hoe"
3
- require "./lib/basis/version.rb"
4
2
 
5
- Hoe.new("basis", Basis::VERSION) do |project|
6
- project.developer("John Barnette", "jbarnette@rubyforge.org")
7
- project.test_globs = ["test/**/*_test.rb"]
3
+ Hoe.plugin :doofus, :git
4
+
5
+ Hoe.spec "basis" do
6
+ developer "John Barnette", "jbarnette@gmail.com"
7
+
8
+ self.extra_rdoc_files = Dir["*.rdoc"]
9
+ self.history_file = "CHANGELOG.rdoc"
10
+ self.readme_file = "README.rdoc"
11
+ self.testlib = :minitest
12
+
13
+ extra_deps << ["erubis", ">= 2", "< 3"]
8
14
  end
data/bin/basis CHANGED
@@ -1,14 +1,94 @@
1
- #!/usr/bin/env ruby -w
1
+ #!/usr/bin/env ruby
2
2
 
3
3
  require "rubygems"
4
+ require "basis"
5
+ require "basis/context"
6
+ require "basis/my"
7
+ require "basis/repo"
8
+ require "optparse"
4
9
 
5
- require "basis/engine"
6
- require "basis/errors"
7
- require "basis/options"
10
+ @defines = {}
11
+ @options = OptionParser.new
12
+
13
+ @options.banner = <<-END
14
+ Usage: basis [options] COMMAND [ARGS]
15
+
16
+ Commands:
17
+ add <git-url> [name] Register a template locally
18
+ list, ls [pattern] List available templates
19
+ remove, rm <name> Remove a template
20
+ update [pattern] Update local templates
21
+
22
+ # add the 'gem:hoe' template
23
+ $ basis add git://github.com/jbarnette/basis-gem-hoe.git
24
+
25
+ # start a new project `foo' using the `gem:hoe' template
26
+ $ basis gem:hoe foo
27
+
28
+ Switches:
29
+ END
30
+
31
+ @options.banner.gsub! /^ /, ""
32
+
33
+ def help
34
+ puts @options.help
35
+ exit
36
+ end
37
+
38
+ def help! message = nil
39
+ warn "fatal: #{message}" if message
40
+ abort @options.help
41
+ end
42
+
43
+ @options.on "-D KEY=VAL", "Define or override a config value" do |kv|
44
+ /^([^=]+)(=(.*))?$/ =~ kv
45
+ key, value = $1, $3 || true
46
+ @defines[key] = value
47
+ end
48
+
49
+ @options.on "--help", "-h", "-?", "Show this help" do
50
+ help
51
+ end
52
+
53
+ @options.on "--version", "-V", "Print #{Basis::VERSION}" do
54
+ puts Basis::Version
55
+ exit
56
+ end
8
57
 
9
58
  begin
10
- options = Basis::Options.parse!(ARGV)
11
- Basis::Engine.new.send(options.verb, options)
12
- rescue Basis::Errors::Reportable => e
13
- abort e.message
59
+ @options.parse! ARGV
60
+ rescue OptionParser::ParseError => e
61
+ help! e.message
62
+ end
63
+
64
+ @repo = Basis::Repo.new
65
+
66
+ # FIX: rescue
67
+
68
+ case command = ARGV.shift
69
+ when "add" then
70
+ url, name = ARGV
71
+ help! "Need a url" unless url
72
+ @repo.add url, name
73
+
74
+ when "ls", "list" then
75
+ @repo.templates(ARGV.shift).each { |name, template| puts name }
76
+
77
+ when "rm", "remove" then
78
+ help! "Need a name" unless name = ARGV.shift
79
+ @repo.remove name
80
+
81
+ when "update" then
82
+ @repo.update ARGV.shift
83
+
84
+ else
85
+ template = @repo.templates[command]
86
+
87
+ help! "Unknown command or template: #{command}" unless template
88
+ help! "Need a destination directory" unless destdir = ARGV.shift
89
+
90
+ my = Basis::My.new File.basename(destdir)
91
+ ctx = Basis::Context.new my, @overrides
92
+
93
+ template.render destdir, ctx
14
94
  end
data/lib/basis.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Basis
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,19 @@
1
+ module Basis
2
+ class Context
3
+ attr_reader :my
4
+
5
+ def initialize my, overrides
6
+ @git = Hash[`git config -lz`.split("\000").map { |e| e.split "\n" }]
7
+ @my = my
8
+ @overrides = overrides || {}
9
+ end
10
+
11
+ def [] key
12
+ @overrides[key] || @my.to_h[key] || @git[key]
13
+ end
14
+
15
+ def git key
16
+ @git[key]
17
+ end
18
+ end
19
+ end
data/lib/basis/my.rb ADDED
@@ -0,0 +1,26 @@
1
+ module Basis
2
+ class My
3
+ attr_reader :classname
4
+ attr_reader :name
5
+ attr_reader :path
6
+ attr_reader :underpath
7
+
8
+ def initialize name
9
+ @name = name
10
+ @path = @name.tr "-", "/"
11
+ @underpath = @path.tr "/", "_"
12
+
13
+ @classname = @name.split("-").
14
+ map { |a| a.split("_").map { |b| b.capitalize }.join }.join "::"
15
+ end
16
+
17
+ def to_h
18
+ @hash ||= {
19
+ "my.classname" => classname,
20
+ "my.name" => name,
21
+ "my.path" => path,
22
+ "my.underpath" => underpath,
23
+ }
24
+ end
25
+ end
26
+ end
data/lib/basis/repo.rb ADDED
@@ -0,0 +1,64 @@
1
+ require "basis/template"
2
+ require "fileutils"
3
+
4
+ module Basis
5
+ class Repo
6
+ attr_reader :home
7
+
8
+ def initialize home = "~/.basis"
9
+ @home = File.expand_path home
10
+ end
11
+
12
+ def add url, name = nil
13
+ name ||= File.basename(url, ".git").
14
+ downcase.sub(/^basis[-_]/, "").tr "-", ":"
15
+
16
+ if templates.keys.include? name
17
+ raise "Template '#{name}' already exists!"
18
+ end
19
+
20
+ FileUtils.mkdir_p template_path
21
+ git :clone, url, template_path(name)
22
+
23
+ @templates = nil
24
+ end
25
+
26
+ def remove name
27
+ FileUtils.rm_rf template_path(name)
28
+
29
+ @templates = nil
30
+ end
31
+
32
+ def templates pattern = nil
33
+ unless @templates
34
+ @templates = {}
35
+
36
+ Dir[template_path("*")].each do |d|
37
+ next unless File.directory? d
38
+
39
+ template = Basis::Template.new d
40
+ @templates[File.basename d] = template
41
+ end
42
+ end
43
+
44
+ Hash[@templates.select { |n, t| pattern.nil? || pattern =~ n }]
45
+ end
46
+
47
+ def update pattern = nil
48
+ templates.each do |name, template|
49
+ next unless pattern.nil? || pattern =~ name
50
+ Dir.chdir(template.srcdir) { git :pull }
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def git *args # FIX
57
+ system "git", *args.map(&:to_s)
58
+ end
59
+
60
+ def template_path *args
61
+ File.join @home, "templates", *args
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,46 @@
1
+ require "erubis"
2
+ require "fileutils"
3
+
4
+ module Basis
5
+ class Template
6
+ attr_reader :srcdir
7
+
8
+ def initialize srcdir
9
+ @srcdir = File.expand_path srcdir
10
+ end
11
+
12
+ def render destdir, context
13
+ Dir.glob("#{srcdir}/**/*", File::FNM_DOTMATCH).each do |src|
14
+ next unless File.file? src
15
+
16
+ rel = src.gsub(/^#{srcdir}\//, "")
17
+ next if /^\.basis/ =~ rel || /^\.git\// =~ rel
18
+
19
+ target = "#{destdir}/#{rel}"
20
+
21
+ target.gsub!(/\[([a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)*)\]/i) do |expr|
22
+ context[$1] || expr
23
+ end
24
+
25
+ FileUtils.mkdir_p File.dirname(target)
26
+
27
+ # FIX: prompt for overwrite?
28
+
29
+ contents = File.read src
30
+
31
+ if contents =~ /\[%.*%\]/
32
+ File.open target, "wb" do |f|
33
+ erb = Erubis::Eruby.new contents,
34
+ :filename => rel, :pattern => '\[% %\]'
35
+
36
+ f.write erb.evaluate(context)
37
+ end
38
+ else
39
+ FileUtils.copy src, target
40
+ end
41
+
42
+ # FIX: file perms
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ require "minitest/autorun"
2
+ require "basis/context"
3
+ require "basis/my"
4
+
5
+ class BasisContextTest < MiniTest::Unit::TestCase
6
+ def setup
7
+ my = Basis::My.new "hello"
8
+ @context = Basis::Context.new my, "my.name" => "HI!", "new" => "new"
9
+ end
10
+
11
+ def test_git # only works if your git is properly set up at test-time
12
+ refute_nil @context.git("user.name")
13
+ assert_equal @context.git("user.name"), @context["user.name"]
14
+ end
15
+
16
+ def test_indexer
17
+ assert_equal "HI!", @context["my.name"]
18
+ assert_equal "new", @context["new"]
19
+ assert_equal "Hello", @context["my.classname"]
20
+ end
21
+
22
+ def test_my
23
+ assert_equal "hello", @context.my.name
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ require "minitest/autorun"
2
+ require "basis/my"
3
+
4
+ class BasisMyTest < MiniTest::Unit::TestCase
5
+ def setup
6
+ @my = Basis::My.new "rake-remote_task"
7
+ end
8
+
9
+ def test_classname
10
+ assert_equal "Rake::RemoteTask", @my.classname
11
+ end
12
+
13
+ def test_initialize
14
+ m = Basis::My.new "foo"
15
+ assert_equal "foo", m.name
16
+ end
17
+
18
+ def test_path
19
+ assert_equal "rake/remote_task", @my.path
20
+ end
21
+
22
+ def test_to_h
23
+ h = @my.to_h
24
+
25
+ assert_equal @my.classname, h["my.classname"]
26
+ assert_equal @my.name, h["my.name"]
27
+ assert_equal @my.path, h["my.path"]
28
+ assert_equal @my.underpath, h["my.underpath"]
29
+ end
30
+
31
+ def test_underpath
32
+ assert_equal "rake_remote_task", @my.underpath
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ require "minitest/autorun"
2
+ require "basis/template"
3
+
4
+ class BasisTemplateTest < MiniTest::Unit::TestCase
5
+ def test_initialize
6
+ t = Basis::Template.new "foo/bar"
7
+ assert_equal "#{File.expand_path '.'}/foo/bar", t.srcdir
8
+ end
9
+ end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: basis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - John Barnette
@@ -9,83 +15,126 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2008-04-17 00:00:00 -07:00
18
+ date: 2010-07-21 00:00:00 -07:00
13
19
  default_executable:
14
20
  dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: erubis
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 2
32
+ version: "2"
33
+ - - <
34
+ - !ruby/object:Gem::Version
35
+ hash: 5
36
+ segments:
37
+ - 3
38
+ version: "3"
39
+ type: :runtime
40
+ version_requirements: *id001
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubyforge
43
+ prerelease: false
44
+ requirement: &id002 !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ hash: 7
50
+ segments:
51
+ - 2
52
+ - 0
53
+ - 4
54
+ version: 2.0.4
55
+ type: :development
56
+ version_requirements: *id002
15
57
  - !ruby/object:Gem::Dependency
16
58
  name: hoe
17
- version_requirement:
18
- version_requirements: !ruby/object:Gem::Requirement
59
+ prerelease: false
60
+ requirement: &id003 !ruby/object:Gem::Requirement
61
+ none: false
19
62
  requirements:
20
63
  - - ">="
21
64
  - !ruby/object:Gem::Version
22
- version: 1.5.1
23
- version:
24
- description: Basis is smart project skeletons. This is a very, very early release. Basis only knows how to deal with git:// urls and local file paths right now. Also, there's no documentation, no way to track remote template lists, dubious cache update semantics, bad command-line messaging, bad error reporting, and bad code. Honestly, installing this gem will probably melt your system. Basis owes a ton to Hoe, Mr. Bones, Rubigen, Newgem, and skel.
65
+ hash: 21
66
+ segments:
67
+ - 2
68
+ - 6
69
+ - 1
70
+ version: 2.6.1
71
+ type: :development
72
+ version_requirements: *id003
73
+ description: |-
74
+ Basis is a project skeleton generator.
75
+
76
+ It'll have more docs at some point.
25
77
  email:
26
- - jbarnette@rubyforge.org
78
+ - jbarnette@gmail.com
27
79
  executables:
28
80
  - basis
29
81
  extensions: []
30
82
 
31
83
  extra_rdoc_files:
32
- - History.txt
33
84
  - Manifest.txt
34
- - README.txt
35
- - test/fixtures/local/project.name/project.name.txt
85
+ - CHANGELOG.rdoc
86
+ - README.rdoc
36
87
  files:
37
- - History.txt
88
+ - .autotest
89
+ - CHANGELOG.rdoc
38
90
  - Manifest.txt
39
- - README.txt
91
+ - README.rdoc
40
92
  - Rakefile
41
93
  - bin/basis
42
- - lib/basis/engine.rb
43
- - lib/basis/errors.rb
44
- - lib/basis/options.rb
45
- - lib/basis/templates.rb
46
- - lib/basis/templates/base.rb
47
- - lib/basis/templates/git.rb
48
- - lib/basis/templates/list.rb
49
- - lib/basis/templates/local.rb
50
- - lib/basis/templates/state.rb
51
- - lib/basis/version.rb
52
- - lib/templates.yml
53
- - test/basis/engine_test.rb
54
- - test/basis/options_test.rb
55
- - test/basis/templates/base_test.rb
56
- - test/basis/templates_test.rb
57
- - test/fixtures/local/erb/erb.txt.erb
58
- - test/fixtures/local/project.name/project.name.txt
59
- - test/helper.rb
94
+ - lib/basis.rb
95
+ - lib/basis/context.rb
96
+ - lib/basis/my.rb
97
+ - lib/basis/repo.rb
98
+ - lib/basis/template.rb
99
+ - test/test_basis_context.rb
100
+ - test/test_basis_my.rb
101
+ - test/test_basis_template.rb
60
102
  has_rdoc: true
61
103
  homepage: http://github.com/jbarnette/basis
104
+ licenses: []
105
+
62
106
  post_install_message:
63
107
  rdoc_options:
64
108
  - --main
65
- - README.txt
109
+ - README.rdoc
66
110
  require_paths:
67
111
  - lib
68
112
  required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
69
114
  requirements:
70
115
  - - ">="
71
116
  - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
72
120
  version: "0"
73
- version:
74
121
  required_rubygems_version: !ruby/object:Gem::Requirement
122
+ none: false
75
123
  requirements:
76
124
  - - ">="
77
125
  - !ruby/object:Gem::Version
126
+ hash: 3
127
+ segments:
128
+ - 0
78
129
  version: "0"
79
- version:
80
130
  requirements: []
81
131
 
82
132
  rubyforge_project: basis
83
- rubygems_version: 1.1.1
133
+ rubygems_version: 1.3.7
84
134
  signing_key:
85
- specification_version: 2
86
- summary: Basis is smart project skeletons
135
+ specification_version: 3
136
+ summary: Basis is a project skeleton generator
87
137
  test_files:
88
- - test/basis/engine_test.rb
89
- - test/basis/options_test.rb
90
- - test/basis/templates/base_test.rb
91
- - test/basis/templates_test.rb
138
+ - test/test_basis_context.rb
139
+ - test/test_basis_my.rb
140
+ - test/test_basis_template.rb
data/History.txt DELETED
@@ -1,3 +0,0 @@
1
- === 0.0.1 / 2008-04-17
2
-
3
- * Initial pre-release.
data/README.txt DELETED
@@ -1,67 +0,0 @@
1
- = basis
2
-
3
- * http://github.com/jbarnette/basis
4
-
5
- == DESCRIPTION:
6
-
7
- Basis is smart project skeletons. This is a very, very early release. Basis only
8
- knows how to deal with git:// urls and local file paths right now. Also, there's
9
- no documentation, no way to track remote template lists, dubious cache update
10
- semantics, bad command-line messaging, bad error reporting, and bad code.
11
-
12
- Honestly, installing this gem will probably melt your system.
13
-
14
- Basis owes a ton to Hoe, Mr. Bones, Rubigen, Newgem, and skel.
15
-
16
- == SYNOPSIS:
17
-
18
- # List all available templates:
19
- basis list
20
-
21
- # Add a template to the local list:
22
- basis add -n rails:example git://github.com/jbarnette/basis-rails.git
23
-
24
- # Remove a template from the local list:
25
- basis remove rails:example
26
-
27
- # Show a local template's configuration:
28
- basis show rails:example
29
-
30
- # Update a local template (or all, without a template name):
31
- basis update rails:example
32
-
33
- # Generate a project in ./monkeys:
34
- basis rails:example monkeys
35
-
36
- == REQUIREMENTS:
37
-
38
- * Subversion and Git (for some templates)
39
-
40
- == INSTALL:
41
-
42
- sudo gem install basis
43
-
44
- == LICENSE:
45
-
46
- (The MIT License)
47
-
48
- Copyright (c) 2008 John Barnette <jbarnette@rubyforge.org>
49
-
50
- Permission is hereby granted, free of charge, to any person obtaining
51
- a copy of this software and associated documentation files (the
52
- 'Software'), to deal in the Software without restriction, including
53
- without limitation the rights to use, copy, modify, merge, publish,
54
- distribute, sublicense, and/or sell copies of the Software, and to
55
- permit persons to whom the Software is furnished to do so, subject to
56
- the following conditions:
57
-
58
- The above copyright notice and this permission notice shall be
59
- included in all copies or substantial portions of the Software.
60
-
61
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
62
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
63
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
64
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
65
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
66
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
67
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/lib/basis/engine.rb DELETED
@@ -1,78 +0,0 @@
1
- require "pathname"
2
-
3
- require "basis/templates"
4
-
5
- module Basis
6
- class Engine
7
- attr_reader :home
8
-
9
- def initialize(home="~/.basis")
10
- @home = File.expand_path(home)
11
- end
12
-
13
- def list(options)
14
- return if templates.empty?
15
-
16
- name_width = templates.collect { |t| t.name.size }.max
17
- desc_width = 80 - name_width - 4
18
-
19
- templates.each do |template|
20
- desc = template.description || "(no description)"
21
- desc = desc[0, desc_width - 3] + "..." if desc.size > desc_width
22
- printf("%-#{name_width}s # #{desc}\n", template.name)
23
- end
24
- end
25
-
26
- def remove(options)
27
- templates.reject! { |t| t.name == options.name }
28
- templates.write!
29
- end
30
-
31
- def add(options)
32
- if templates.detect { |t| t.name == options.name || t.url == options.source }
33
- raise Errors::TemplateAlreadyExists.new(options.name, options.source)
34
- end
35
-
36
- template = Templates.create(self, options.source, :name => options.name)
37
- template.update!
38
-
39
- templates << template
40
- templates.write!
41
- end
42
-
43
- def generate(options)
44
- find_template(options.name).generate(options.destination)
45
- end
46
-
47
- def update(options)
48
- templates.select {|t| options.name.nil? || t.name == options.name }.each { |t| t.update! }
49
- end
50
-
51
- def show(options)
52
- # FIXME: terrible
53
- puts YAML.dump(find_template(options.name))
54
- end
55
-
56
- protected
57
-
58
- def find_template(name)
59
- template = templates.detect {|t| t.name == name }
60
- raise Errors::TemplateNotFound.new(name) unless template
61
- template
62
- end
63
-
64
- def templates
65
- @templates ||= begin
66
- template = Pathname.new(__FILE__).dirname + "../templates.yml"
67
- file = Pathname.new(@home) + "templates.yml"
68
-
69
- unless file.exist?
70
- file.dirname.mkpath
71
- FileUtils.cp(template, file)
72
- end
73
-
74
- Templates::List.new(self, file)
75
- end
76
- end
77
- end
78
- end
data/lib/basis/errors.rb DELETED
@@ -1,29 +0,0 @@
1
- module Basis
2
- module Errors
3
- class Reportable < StandardError; end
4
-
5
- class TemplateAlreadyExists < Reportable
6
- def initialize(name, url)
7
- super("'#{name || url}' is already a template")
8
- end
9
- end
10
-
11
- class DestinationAlreadyExists < Reportable
12
- def initialize(destination)
13
- super("#{destination} already exists")
14
- end
15
- end
16
-
17
- class TemplateNotFound < Reportable
18
- def initialize(name)
19
- super("template not found: #{name}")
20
- end
21
- end
22
-
23
- class UnknownTemplateScheme < Reportable
24
- def initialize(raw_url)
25
- super("don't know how to load '#{raw_url}'")
26
- end
27
- end
28
- end
29
- end
data/lib/basis/options.rb DELETED
@@ -1,98 +0,0 @@
1
- require "optparse"
2
-
3
- require "basis/version"
4
-
5
- module Basis
6
- class Options
7
- VALID_VERBS = %w(add remove list update show)
8
-
9
- attr_reader :source, :destination, :name, :verb
10
-
11
- class << self
12
- alias_method :parse!, :new
13
- end
14
-
15
- def initialize(*args)
16
- argv = args.flatten
17
-
18
- parser = OptionParser.new do |parser|
19
- parser.banner = "Usage: basis [options] [verb]"
20
- parser.version = Basis::VERSION
21
-
22
- parser.on("-h", "-?", "--help", "Show this message") do
23
- puts parser
24
- exit
25
- end
26
-
27
- parser.on("-v", "--version", "Show version") do
28
- puts Basis::VERSION
29
- exit
30
- end
31
-
32
- parser.on("-n", "--name [NAME]", "Override an added template's name") do |name|
33
- @name = name
34
- end
35
-
36
- # FIXME: This is lame. Document it better and stop misusing parser.separator.
37
-
38
- parser.separator ""
39
- parser.separator "# List all available templates:"
40
- parser.separator "basis list"
41
-
42
- parser.separator ""
43
- parser.separator "# Add a template to the local list:"
44
- parser.separator "basis add -n rails:edge git://github.com/jbarnette/basis-rails-edge.git"
45
-
46
- parser.separator ""
47
- parser.separator "# Remove a template from the local list:"
48
- parser.separator "basis remove rails:edge"
49
-
50
- parser.separator ""
51
- parser.separator "# Show a local template's configuration:"
52
- parser.separator "basis show rails:edge"
53
-
54
- parser.separator ""
55
- parser.separator "# Update a local template (or all, without a template name):"
56
- parser.separator "basis update rails:edge"
57
-
58
- parser.separator ""
59
- parser.separator "# Generate a project in ./monkeys:"
60
- parser.separator "basis rails:edge monkeys"
61
- parser.separator ""
62
- end
63
-
64
- parser.parse!(argv)
65
-
66
- verb_or_template_name = argv.shift
67
-
68
- if VALID_VERBS.include?(verb_or_template_name)
69
- @verb = verb_or_template_name
70
-
71
- case @verb
72
- when "add" then @source = shift_required_arg(parser, argv)
73
- when "remove" then @name = shift_required_arg(parser, argv)
74
- when "show" then @name = shift_required_arg(parser, argv)
75
- when "update" then @name = argv.shift
76
- end
77
-
78
- else
79
- @verb = "generate"
80
- @name = verb_or_template_name
81
- @destination = shift_required_arg(parser, argv)
82
- end
83
- end
84
-
85
- private
86
-
87
- def shift_required_arg(parser, argv)
88
- arg = argv.shift
89
-
90
- unless arg
91
- puts parser
92
- exit 1
93
- end
94
-
95
- arg
96
- end
97
- end
98
- end
@@ -1,28 +0,0 @@
1
- require "basis/templates/base"
2
- require "basis/templates/list"
3
- require "basis/templates/state"
4
-
5
- require "basis/templates/local"
6
- require "basis/templates/git"
7
-
8
- require "uri"
9
-
10
- module Basis
11
- module Templates
12
- def self.create(engine, raw_url, options={})
13
- uri = URI.parse(raw_url)
14
-
15
- if uri.scheme.nil?
16
- uri = URI.parse("file://#{File.expand_path(uri.path)}")
17
- end
18
-
19
- klass = case uri.scheme
20
- when "file" then Local
21
- when "git" then Git
22
- else raise Errors::UnknownTemplateScheme.new(raw_url)
23
- end
24
-
25
- klass.new(engine, uri, options)
26
- end
27
- end
28
- end
@@ -1,72 +0,0 @@
1
- require "erb"
2
- require "fileutils"
3
- require "pathname"
4
-
5
- require "basis/errors"
6
- require "basis/templates/state"
7
-
8
- module Basis
9
- module Templates
10
- class Base
11
- attr_reader :url, :name, :description
12
-
13
- def initialize(engine, url, options={})
14
- raise ArgumentError, "source URL is required" unless url
15
-
16
- @engine = engine
17
- @url = url
18
- @name = options[:name] || url.path.split("/").last
19
- @description = options[:description]
20
- end
21
-
22
- def update!
23
- raise NotImplementedError, "implement in subclasses"
24
- end
25
-
26
- def generate(destination)
27
- srcpath = Pathname.new(cache_dir)
28
- destpath = Pathname.new(destination)
29
- state = State.new(destpath)
30
-
31
- raise Errors::DestinationAlreadyExists.new(destination) if destpath.exist?
32
- update! unless cached?
33
-
34
-
35
- Pathname.glob(srcpath + "**" + "*").each do |src|
36
- next unless src.file?
37
-
38
- dest = destination_for(src, :from => srcpath, :to => destpath)
39
- dest.dirname.mkpath
40
-
41
- if erb?(src)
42
- dest.open("w") { |d| d.write(ERB.new(src.read).result(state.binding)) }
43
- else
44
- FileUtils.copy(src, dest)
45
- end
46
- end
47
- end
48
-
49
- protected
50
-
51
- def cached?
52
- File.directory?(cache_dir)
53
- end
54
-
55
- def cache_dir
56
- @cache_dir ||= File.join(@engine.home, "cache", "#{url.path.split("/").last}-#{name.hash.abs}")
57
- end
58
-
59
- private
60
-
61
- def erb?(path)
62
- path.extname == ".erb"
63
- end
64
-
65
- def destination_for(src, options={})
66
- dest = src.relative_path_from(options[:from]).expand_path(options[:to])
67
- dest = dest.dirname + dest.basename.to_s[0...-4] if erb?(src)
68
- Pathname.new(dest.to_s.gsub("project.name", options[:to].basename))
69
- end
70
- end
71
- end
72
- end
@@ -1,15 +0,0 @@
1
- require "fileutils"
2
-
3
- module Basis
4
- module Templates
5
- class Git < Base
6
- def update!
7
- if File.directory?(cache_dir)
8
- Dir.chdir(cache_dir) { system "git pull" }
9
- else
10
- system "git clone #{url.to_s} #{cache_dir}"
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,28 +0,0 @@
1
- require "YAML"
2
-
3
- module Basis
4
- module Templates
5
- class List < Array
6
- def initialize(engine, file)
7
- @engine = engine
8
- @file = file
9
-
10
- YAML.load(IO.read(@file)).each do |name, data|
11
- self << Templates.create(@engine, data["url"],
12
- :name => name, :description => data["description"])
13
- end
14
-
15
- sort! { |a, b| a.name <=> b.name }
16
- end
17
-
18
- def write!(file=@file)
19
- hashified = {}
20
- each { |t| hashified[t.name] = { "url" => t.url.to_s, "description" => t.description } }
21
-
22
- File.open(file, "w") do |f|
23
- f.write(YAML.dump(hashified))
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,13 +0,0 @@
1
- require "fileutils"
2
-
3
- module Basis
4
- module Templates
5
- class Local < Base
6
- def update!
7
- FileUtils.rmtree(cache_dir)
8
- FileUtils.mkdir_p(cache_dir)
9
- FileUtils.cp_r(Dir.glob(File.join(url.path, "*")), cache_dir)
10
- end
11
- end
12
- end
13
- end
@@ -1,27 +0,0 @@
1
- module Basis
2
- module Templates
3
- class State
4
- public :binding
5
- attr_reader :project
6
-
7
- def initialize(destination)
8
- @project = Project.new(destination)
9
- end
10
-
11
- private
12
-
13
- class Project
14
- attr_reader :directory, :name
15
-
16
- def initialize(destination)
17
- @directory = destination.to_s
18
- @name = destination.basename.to_s
19
-
20
- def @name.classify
21
- gsub(/(?:^|_)(.)/) { $1.upcase }
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end
data/lib/basis/version.rb DELETED
@@ -1,3 +0,0 @@
1
- module Basis
2
- VERSION = "0.0.1"
3
- end
data/lib/templates.yml DELETED
@@ -1,7 +0,0 @@
1
- "gem:hoe":
2
- description: A new RubyGem, powered by Hoe!
3
- url: git://github.com/jbarnette/basis-gem-hoe.git
4
-
5
- rails:
6
- description: A clean Rails 2.0 app.
7
- url: git://github.com/jbarnette/basis-rails.git
@@ -1,12 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "/../helper"))
2
-
3
- require "basis/engine"
4
-
5
- module Basis
6
- class EngineTest < Test::Unit::TestCase
7
- def test_has_some_sane_defaults_for_home
8
- engine = Basis::Engine.new
9
- assert_equal(File.expand_path("~/.basis"), engine.home)
10
- end
11
- end
12
- end
@@ -1,38 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "/../helper"))
2
-
3
- require "basis/options"
4
-
5
- module Basis
6
- class OptionsTest < Test::Unit::TestCase
7
- def test_list
8
- opts = Basis::Options.parse!("list")
9
- assert_equal("list", opts.verb)
10
- end
11
-
12
- def test_add
13
- opts = Basis::Options.parse!("add", "someurl")
14
- assert_equal("add", opts.verb)
15
- assert_equal("someurl", opts.source)
16
- end
17
-
18
- def test_add_with_explicit_name
19
- opts = Basis::Options.parse!("add", "-n", "monkeys", "someurl")
20
- assert_equal("add", opts.verb)
21
- assert_equal("someurl", opts.source)
22
- assert_equal("monkeys", opts.name)
23
- end
24
-
25
- def test_remove
26
- opts = Basis::Options.parse!("remove", "sometemplate")
27
- assert_equal("remove", opts.verb)
28
- assert_equal("sometemplate", opts.name)
29
- end
30
-
31
- def test_generate
32
- opts = Basis::Options.parse!("sometemplate", "whereto")
33
- assert_equal("generate", opts.verb)
34
- assert_equal("sometemplate", opts.name)
35
- assert_equal("whereto", opts.destination)
36
- end
37
- end
38
- end
@@ -1,85 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "/../../helper"))
2
-
3
- require "fileutils"
4
- require "tmpdir"
5
- require "uri"
6
-
7
- require "basis/templates/base"
8
-
9
- module Basis
10
- module Templates
11
- class BaseTest < Test::Unit::TestCase
12
- PROJECT_NAME = "rendered_project"
13
- PROJECT_CLASS_NAME = "RenderedProject"
14
- PROJECT_DIR = File.join("/tmp", PROJECT_NAME)
15
-
16
- class MockTemplate < Templates::Base
17
- def initialize; super(nil, URI.parse(LOCAL_TEMPLATE_PATH)); end
18
- def update!; end
19
- def cache_dir; LOCAL_TEMPLATE_PATH; end
20
- end
21
-
22
- def setup
23
- FileUtils.rm_rf(PROJECT_DIR)
24
- end
25
-
26
- def test_requires_a_url
27
- assert_raise(ArgumentError) { Base.new(nil, nil) }
28
- end
29
-
30
- def test_uses_last_path_component_as_name_by_default
31
- t = Base.new(nil, URI.parse("~/work/monkeys"))
32
- assert_equal("monkeys", t.name)
33
- end
34
-
35
- def test_can_override_name
36
- t = Base.new(nil, URI.parse("~/work/monkeys"), :name => "lemurs")
37
- assert_equal("lemurs", t.name)
38
- end
39
-
40
- def test_can_specify_an_optional_description
41
- t = Base.new(nil, URI.parse("~/work/monkeys"), :description => "hai")
42
- assert_equal("hai", t.description)
43
- end
44
-
45
- def test_requires_subclasses_to_implement_update
46
- base = Base.new(nil, URI.parse("~/work/monkeys"))
47
- base.stubs(:cache_dir).returns(true)
48
-
49
- assert_raise(NotImplementedError) { base.update! }
50
- end
51
-
52
- def test_complains_about_generating_if_dest_exists
53
- Dir.mkdir(PROJECT_DIR)
54
- assert_raise(Errors::DestinationAlreadyExists) { MockTemplate.new.generate(PROJECT_DIR) }
55
- end
56
-
57
- def test_transforms_project_name_in_directory_names
58
- MockTemplate.new.generate(PROJECT_DIR)
59
-
60
- destdir = File.join(PROJECT_DIR, PROJECT_NAME)
61
- assert(File.directory?(destdir), "#{destdir} exists and is a directory")
62
- end
63
-
64
- def test_transforms_project_name_in_file_names
65
- MockTemplate.new.generate(PROJECT_DIR)
66
-
67
- destfile = File.join(PROJECT_DIR, PROJECT_NAME, "#{PROJECT_NAME}.txt")
68
- assert(File.file?(destfile), "#{destfile} exists and is a file")
69
- end
70
-
71
- def test_renders_erb_templates
72
- MockTemplate.new.generate(PROJECT_DIR)
73
- erbfile = Pathname.new(File.join(PROJECT_DIR, "erb", "erb.txt"))
74
- assert(erbfile.exist?, "#{erbfile} exists")
75
-
76
- lines = erbfile.readlines.collect { |l| l.chomp }
77
-
78
- assert_equal(3, lines.size)
79
- assert_equal(PROJECT_NAME, lines[0])
80
- assert_equal(PROJECT_CLASS_NAME, lines[1])
81
- assert_equal(PROJECT_DIR, lines[2])
82
- end
83
- end
84
- end
85
- end
@@ -1,19 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "/../helper"))
2
-
3
- require "basis/templates"
4
-
5
- module Basis
6
- class TemplatesTest < Test::Unit::TestCase
7
- def test_local_from_simple_path
8
- assert_kind_of(Templates::Local, Templates.create(nil, LOCAL_TEMPLATE_PATH))
9
- end
10
-
11
- def test_git_from_git_scheme_url
12
- assert_kind_of(Templates::Git, Templates.create(nil, "git://foo"))
13
- end
14
-
15
- def test_complains_about_unhandled_url_schemes
16
- assert_raise(Errors::UnknownTemplateScheme) { Templates.create(nil, "ether://monkeys") }
17
- end
18
- end
19
- end
@@ -1,3 +0,0 @@
1
- <%= project.name %>
2
- <%= project.name.classify %>
3
- <%= project.directory %>
File without changes
data/test/helper.rb DELETED
@@ -1,9 +0,0 @@
1
- require "rubygems"
2
- require "test/unit"
3
- require "mocha"
4
-
5
- %w(../lib).each do |path|
6
- $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), path)))
7
- end
8
-
9
- LOCAL_TEMPLATE_PATH = File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "local"))