basis 0.0.1 → 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/.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"))