nake 0.0.7 → 0.0.8.pre

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -29,3 +29,20 @@
29
29
 
30
30
  = Version 0.0.7
31
31
  * Added Task#boot method for setting some stuff after other tasks boot
32
+ * Added DSL helper desc
33
+ * Removed task aliases
34
+
35
+ = Version 0.0.8
36
+ * Added Nake::Template & template helper
37
+ * Added Nake::ErbTemplate & erb helper
38
+ * Added bin/snake for system-wide tasks
39
+ * Added AbstractTask base class
40
+ * Exit with the status of the spec command to help CI stuff out some
41
+ * "nake --H build" can provide more informations about given task
42
+ * Task.description can use %{foo} and it will be replaced by values from its config hash
43
+ * Task.description can be a callable object
44
+
45
+ = Version 0.0.9
46
+ * Thanks to Task#config=, the configuration can be shared between multiple tasks
47
+ * Reworked rule, added Rule class
48
+ * Added --coloring & --no-coloring options
@@ -8,7 +8,7 @@ Sounds terrible? Well and it's not all! Let's take a look at this "example":http
8
8
 
9
9
  h1. Features
10
10
 
11
- - Tasks can have a *name*, *description*, *dependencies*, *aliases* and *blocks* which will be executed when the task is called. Task can be also hidden if you don't want to list it in the list of available tasks.
11
+ - Tasks can have a *name*, *description*, *dependencies*, and *blocks* which will be executed when the task is called. Task can be also hidden if you don't want to list it in the list of available tasks.
12
12
  - You can use `nake` in *shebang*, so you can use your file with tasks as a runner.
13
13
  - *Arguments parsing*, everything what start with @--@ will be passed into options hash and everything other will be treated as an arguments. Both arguments and options will be passed as a block arguments for task, so you don't have to learn any new API, just use normal Ruby expressions as you are used to. Options are parsed into Ruby data types, so if you have @--without-mysql@, you'll get @{mysql: false}@, if you have @--name=botanicus@, you'll get @{name: "botanicus"}@ etc.
14
14
  - *Configuration support*, so you don't have to use bunch of constants as in Rake. Example: @Task[:clean].config[:files] = Dir.glob("*.gem")@
@@ -16,48 +16,24 @@ h1. Features
16
16
  - Two level of API for defining tasks. @task@ helper is useful for defining simple tasks and if you need something more complicated, you can use @Task.new@
17
17
  - *Interactive session* if you run @nake -i@ or @nake -i task@ you get an interactive nake session.
18
18
 
19
- h1. Usage
20
-
21
- First of all there is a bunch of "examples":github.com/botanicus/nake/tree/master/examples, so you can try them. All these scripts are executable, so just run @./executable/basic.rb -T@ and that's it!
22
-
23
- h1. Documentation
24
-
25
- h2. Tasks
26
-
27
- h3. Options parsing
28
-
29
- h2. File Tasks
30
-
31
- h2. Task Helpers
32
-
33
- h2. Available Tasks
19
+ h1. Installation
34
20
 
35
- h3. Built-in Tasks
21
+ _Before installation, please ensure that you are running on Ruby 1.9 or higher, Ruby 1.8 isn't supported!_
36
22
 
37
- - @-T@
38
- - @-H@
39
- - @-i@
23
+ * From Gemcutter: @gem install nake@
24
+ * JRuby: @jruby --1.9 -S gem install nake@
25
+ * Install edge version via "Rip":http://hellorip.com: @rip install git://github.com/botanicus/nake.git@
26
+ * Install tagged version via "Rip":http://hellorip.com: @rip install git://github.com/botanicus/nake.git 0.1@
40
27
 
41
- h3. File @nake/tasks/bundle@
42
-
43
- This file contains only @bundle@ task which will load bundler @--no-cached@
44
-
45
- h3. File @nake/tasks/clean@
46
-
47
- h3. File @nake/tasks/gem@
48
-
49
- h3. File @nake/tasks/release@
50
-
51
- h3. File @nake/tasks/rip@
28
+ h1. Usage
52
29
 
53
- h3. File @nake/tasks/spec@
30
+ First of all there is a bunch of "examples":github.com/botanicus/nake/tree/master/examples, so you can try them. All these scripts are executable, so just run @./executable/basic.rb -T@ and that's it!
54
31
 
55
32
  h1. Links
56
33
 
34
+ * "Nake Wiki":http://wiki.github.com/botanicus/nake
57
35
  * "RDoc.info API Docs":http://rdoc.info/projects/botanicus/nake
58
36
  * "Yardoc.org API Docs":http://yardoc.org/docs/botanicus-nake
59
37
  * "Examples":http://github.com/botanicus/nake/tree/master/examples
60
38
  * "Bug reporting":http://github.com/botanicus/nake/issues
61
39
  * "Caliper Code Metrics":http://devver.net/caliper/project?repo=git%3A%2F%2Fgithub.com%2Fbotanicus%2Fnake.git
62
-
63
- * http://github.com/botanicus/filelist
data/TODO.txt CHANGED
@@ -1,5 +1,22 @@
1
- - Task#setup
1
+ === 0.1 ===
2
+ - README
3
+ - update examples
4
+ - features
5
+
6
+ - rework rule
7
+ - check if everything works
8
+ - specs
9
+ - update benchmarks
2
10
  - yardoc
3
- - specs & features
4
- - better argv parsing maybe, task(:spec) do |*paths, options| is fine, but task(:spec) do |path, options| will fail if no path specified ... but actually task(:spec) do |path = "spec", options| might be fine, try it ... BTW task(["-i", "--interactive"]) do |task, *args, options| doesn't work ... putting options as a first argument should solve everything, but it's not very intuitive :/
5
- - how to solve args inheriting (like if we have task release which depends on task build which takes a gemspec as an argument)
11
+ - refactor bin/nake
12
+
13
+ === 0.2 ===
14
+ Task.new(:test) do |task|
15
+ task.options[:optional] = [:force] # maybe {force: :boolean}
16
+ task.options[:required] = [:name]
17
+ end
18
+ => better -T list + validations
19
+
20
+ === 0.3 ===
21
+ - nrake & nake/rake for running rake tasks in nake
22
+ - rake2nake
data/bin/nake CHANGED
@@ -61,3 +61,6 @@ rescue SystemExit => exception
61
61
  rescue Exception => exception
62
62
  print_exception_with_backtrace_and_abort(exception)
63
63
  end
64
+
65
+ # exit with exit status of the last command
66
+ exit $? ? $?.exitstatus : 0
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env nake
2
+
3
+ # Run rake tasks with nake
4
+ require "nake/rake"
@@ -0,0 +1 @@
1
+ #!/usr/bin/env ruby
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env nake
2
+
3
+ # Snake is similar to sake http://www.rubyinside.com/sake-system-wide-rake-tasks-543.html
4
+
5
+ # tasks
6
+
7
+ # snake get db_tasks.rb
8
+ # snake get http://gist.github.com/raw/266818/7239049c59b32d07a8af7e26f89190b61e0a7860/snake.rb
9
+ Task.new(:get) do |task|
10
+ task.description = "Add tasks from given file or URL to your %{task_file}"
11
+
12
+ task.define do |path|
13
+ require "open-uri"
14
+ begin
15
+ open(path) do |stream|
16
+ File.open(self.config[:task_file], "a") do |file|
17
+ file.puts(stream.read, "")
18
+ end
19
+ end
20
+ rescue Exception => exception
21
+ abort exception.message
22
+ end
23
+ end
24
+ end
25
+
26
+ Task.new(:edit) do |task|
27
+ task.config = Task[:get].config
28
+ task.description = "Edit %{task_file} in your editor"
29
+
30
+ task.define do
31
+ exec((ENV["EDITOR"] || "vim"), task.config[:task_file])
32
+ end
33
+ end
34
+
35
+ # setup
36
+ Task[:get].config[:task_file] = File.expand_path("~/.tasks.rb")
37
+
38
+ # run
39
+ if File.exist?(Task[:get].config[:task_file])
40
+ load Task[:get].config[:task_file]
41
+ end
@@ -0,0 +1,28 @@
1
+ desc "Simple task"
2
+ task :simple do
3
+ puts "Hello World!"
4
+ end
5
+
6
+ desc "Namespaced task"
7
+ task "a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z" do
8
+ # do nothing
9
+ end
10
+
11
+ desc "Task with arguments"
12
+ task :arguments
13
+
14
+ desc "Task with dependencies"
15
+ task :dependencies
16
+
17
+ directory "tmp/www"
18
+
19
+ desc "Generate tmp/www/index.html"
20
+ file "tmp/www/index.html" => "tmp/www" do |task|
21
+ File.open(task.name, "w") do |file|
22
+ file.puts("<html>Hello World!</html>")
23
+ end
24
+ end
25
+
26
+ rule ".o" => [".c"] do |task|
27
+ sh "gcc #{task.source} -c -o #{task.name}"
28
+ end
data/bm/bms.rb CHANGED
@@ -10,13 +10,47 @@ nake = "./bin/nake"
10
10
  abort "You have to install Rake!" if rake.empty?
11
11
  puts "Using nake from #{nake} and rake from #{rake}\n\n"
12
12
 
13
+ def run(command)
14
+ system("#{command} &> /dev/null") || abort("Problem during running #{command}")
15
+ end
16
+
13
17
  # Make sure you are running both Rake and Nake on the same Ruby version!
14
18
  RBench.run(10) do
15
19
  column :rake
16
20
  column :nake
17
21
 
18
22
  report "list tasks" do
19
- rake { system("#{rake} -T &> /dev/null") || abort("Problem during running #{rake} -T") }
20
- nake { system("#{nake} -T &> /dev/null") || abort("Problem during running #{nake} -T") }
23
+ rake { run "#{rake} -T" }
24
+ nake { run "#{nake} -T" }
25
+ end
26
+
27
+ report "simple task" do
28
+ rake { run "#{rake} simple" }
29
+ nake { run "#{nake} simple" }
30
+ end
31
+
32
+ report "namespaced task" do
33
+ rake { run "#{rake} a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z" }
34
+ nake { run "#{nake} a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z" }
21
35
  end
36
+
37
+ #report "task with arguments" do
38
+ # rake { run "#{rake} arguments" }
39
+ # nake { run "#{nake} arguments" }
40
+ #end
41
+ #
42
+ #report "task with dependencies" do
43
+ # rake { run "#{rake} dependencies" }
44
+ # nake { run "#{nake} dependencies" }
45
+ #end
46
+
47
+ report "file task" do
48
+ rake { run "#{rake} tmp/www/index.html" }
49
+ nake { run "#{nake} tmp/www/index.html" }
50
+ end
51
+
52
+ #report "rule" do
53
+ # rake { run "#{rake} tmp/test.o" }
54
+ # nake { run "#{nake} tmp/test.o" }
55
+ #end
22
56
  end
@@ -0,0 +1,21 @@
1
+ #!../bin/nake
2
+
3
+ task :simple do
4
+ puts "Hello World!"
5
+ end
6
+
7
+ task "a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z" do
8
+ # do nothing
9
+ end
10
+
11
+ directory "tmp/www"
12
+
13
+ file "tmp/www/index.html", "tmp/www" do |path|
14
+ File.open(path, "w") do |file|
15
+ file.puts("<html>Hello World!</html>")
16
+ end
17
+ end
18
+
19
+ #rule ".o" => [".c"] do |task|
20
+ # sh "gcc #{task.source} -c -o #{task.name}"
21
+ #end
data/deps.rb ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env rip install
2
+
3
+ # Syntax:
4
+ # repository [tag or commit to install]
5
+ git://github.com/flori/term-ansicolor
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env rip install
2
+
3
+ # Syntax:
4
+ # repository [tag or commit to install]
5
+ git://github.com/flori/term-ansicolor
@@ -0,0 +1,33 @@
1
+ desc :release, "Create a new release"
2
+ task(:release) do
3
+ # ...
4
+ end
5
+
6
+ task = task(:release) do
7
+ # ...
8
+ end
9
+ task.description = "Create a new release"
10
+
11
+ task(:release) do
12
+ # ...
13
+ end
14
+ Task[:release].description = "Create a new release"
15
+
16
+ task = task(:release)
17
+ task.description = "Create a new release"
18
+ task.define do
19
+ # ...
20
+ end
21
+
22
+ task(:release)
23
+ Task[:release].description = "Create a new release"
24
+ task(:release) do
25
+ # ...
26
+ end
27
+
28
+ Task.new(:release) do |task|
29
+ task.description = "Create a new release"
30
+ task.define do
31
+ # ...
32
+ end
33
+ end
File without changes
File without changes
File without changes
@@ -1,9 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "nake/task"
4
-
5
3
  module Nake
6
- VERSION ||= "0.0.7"
4
+ VERSION ||= "0.0.8"
7
5
  def self.verbose
8
6
  @@verbose
9
7
  rescue NameError
@@ -24,6 +22,16 @@ module Nake
24
22
  @@debug = boolean
25
23
  end
26
24
 
25
+ def self.coloring
26
+ @@coloring
27
+ rescue NameError
28
+ @@coloring = STDIN.tty?
29
+ end
30
+
31
+ def self.coloring=(boolean)
32
+ @@coloring = boolean
33
+ end
34
+
27
35
  # I was drunk so you might found this code not very clear. But it's clear for me and it works.
28
36
  def self.args
29
37
  @@args ||= begin
@@ -92,5 +100,4 @@ module Nake
92
100
  end
93
101
  end
94
102
 
95
- require "nake/dsl"
96
- require "nake/helpers"
103
+ require "nake/task"
@@ -0,0 +1,175 @@
1
+ # encoding: utf-8
2
+
3
+ require "nake/colors"
4
+ require "nake/argv"
5
+
6
+ module Nake
7
+ TaskNotFound ||= Class.new(StandardError)
8
+ ConfigurationError ||= Class.new(StandardError)
9
+
10
+ class AbstractTask
11
+ def self.[](name)
12
+ self.tasks[name.to_s]
13
+ end
14
+
15
+ def self.[]=(name, task)
16
+ self.tasks[name.to_s] = task
17
+ end
18
+
19
+ # @protected use Task[name] resp. Task[name] = task
20
+ def self.tasks
21
+ @@tasks ||= Hash.new
22
+ end
23
+
24
+ def self.boot
25
+ self.tasks.each do |name, task|
26
+ task.boot!
27
+ end
28
+ end
29
+
30
+ # return existing task if task with given name already exist
31
+ def self.new(name, *dependencies, &block)
32
+ task = self[name]
33
+ task && task.setup(*dependencies, &block) || super(name, *dependencies, &block)
34
+ end
35
+
36
+ attr_accessor :name, :dependencies, :hidden, :original_args
37
+ attr_reader :blocks
38
+ def initialize(name, *dependencies, &block)
39
+ @hidden = false
40
+ @name, @blocks = name.to_sym, Array.new
41
+ @dependencies = Array.new
42
+ self.register
43
+ self.setup(*dependencies, &block)
44
+ end
45
+
46
+ attr_writer :description
47
+ def description
48
+ if @description.respond_to?(:call)
49
+ # task.description = lambda { "Edit #{self.config[:task_file]}" }
50
+ @description.call
51
+ elsif @description
52
+ # task.description = "Edit %{task_file}"
53
+ @description % self.config
54
+ else
55
+ nil
56
+ end
57
+ end
58
+
59
+ attr_writer :config # don't use this if you don't have to!
60
+ def config
61
+ @config ||= begin
62
+ Hash.new do |hash, key|
63
+ raise ConfigurationError, "Configuration key #{key} in task #{name} doesn't exist"
64
+ end.tap do |hash|
65
+ hash.define_singleton_method(:declare) do |*keys|
66
+ keys.each { |key| self[key] = nil unless self.has_key?(key) }
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ def setup(*dependencies, &block)
73
+ self.dependencies.push(*dependencies)
74
+ self.instance_exec(self, &block) if block
75
+ return self
76
+ end
77
+
78
+ def define(&block)
79
+ @blocks.push(block)
80
+ end
81
+
82
+ def hidden?
83
+ @hidden
84
+ end
85
+
86
+ def run(args)
87
+ self.original_args = args
88
+ options = ArgvParser.extract!(args)
89
+ self.call(args, options)
90
+ end
91
+
92
+ # NOTE: the reason why we don't have splat for args is that when we have Task["-T"]
93
+ # which doesn't have any args and options, we wall just call it without any arguments,
94
+ # but when we use splat, then we will have to call it at least with Hash.new for options
95
+ def call(args = Array.new, options = Hash.new)
96
+ unless self.dependencies.empty?
97
+ info "Invoking task #{name}"
98
+ self.invoke_dependencies(*args, options)
99
+ end
100
+ unless self.blocks.empty?
101
+ note "Executing task #{name} with arguments #{args.inspect} and options #{options.inspect}"
102
+ debug "Config #{self.config.inspect}"
103
+ self.blocks.each do |block|
104
+ block.call(*args, options)
105
+ end
106
+ ## we can't use arity, because it returns 0 for lambda { |options = Hash.new| }.arity
107
+ ## if we define method with one optional argument, it will returns -1
108
+ #
109
+ ## better argv parsing maybe, task(:spec) do |*paths, options| is fine, but task(:spec) do |path, options| will fail if no path specified ... but actually task(:spec) do |path = "spec", options| might be fine, try it ... BTW task(["-i", "--interactive"]) do |task, *args, options| doesn't work ... putting options as a first argument should solve everything, but it's not very intuitive :/
110
+ #if RUBY_VERSION >= "1.9.2"
111
+ # raise ArgumentError, "Task can't take block arguments" if args.length + 1 > block.parameters.select { |type, name| type.eql?(:req) || type.eql?(:opt) }.length
112
+ # raise ArgumentError, "Task can't take block arguments" if block.parameters.any? { |type, name| type.eql?(:block) }
113
+ #end
114
+ #
115
+ #if RUBY_VERSION >= "1.9.2" && block.parameters.empty?
116
+ # block.call
117
+ #else
118
+ # block.call(*args, options)
119
+ #end
120
+ end
121
+ end
122
+
123
+ def bootloaders
124
+ @bootloaders ||= Array.new
125
+ end
126
+
127
+ def boot_dependencies
128
+ @boot_dependencies ||= Array.new
129
+ end
130
+
131
+ def boot(*dependencies, &block)
132
+ self.boot_dependencies.push(*dependencies)
133
+ self.bootloaders.push(block)
134
+ end
135
+
136
+ def boot!
137
+ unless self.boot_dependencies.empty? && self.bootloaders.empty?
138
+ note "Booting #{self.name}"
139
+ end
140
+ while dependency = self.boot_dependencies.shift
141
+ self.class[dependency].tap do |task|
142
+ if task.nil?
143
+ raise TaskNotFound, "Task #{dependency} doesn't exist!"
144
+ end
145
+ task.boot!
146
+ end
147
+ end
148
+ while block = self.bootloaders.shift
149
+ block.call
150
+ end
151
+ end
152
+
153
+ def booted?
154
+ self.bootloaders.empty? && self.boot_dependencies.empty?
155
+ end
156
+
157
+ def reset!
158
+ self.dependencies.clear
159
+ self.blocks.clear
160
+ end
161
+
162
+ protected
163
+ def invoke_dependencies(*args, options)
164
+ self.dependencies.each do |name|
165
+ task = self.class[name]
166
+ raise TaskNotFound, "Task with name #{name} doesn't exist" if task.nil?
167
+ task.call(*args, options) # TODO: what about arguments?
168
+ end
169
+ end
170
+
171
+ def register
172
+ self.class[self.name] = self
173
+ end
174
+ end
175
+ end