kicker 3.0.0 → 4.0.0.p1

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.
@@ -0,0 +1,40 @@
1
+ class Kicker
2
+ module CoreExt
3
+ module Array
4
+ # Deletes elements from self for which the block evaluates to +true+. A new
5
+ # array is returned with those values the block returned. So basically, a
6
+ # combination of reject! and map.
7
+ #
8
+ # a = [1,2,3]
9
+ # b = a.take_and_map { |x| x * 2 if x == 2 }
10
+ # b # => [4]
11
+ # a # => [1, 3]
12
+ #
13
+ # If +pattern+ is specified then files matching the pattern will be taken.
14
+ #
15
+ # a = [ 'bar', 'foo/bar' ]
16
+ # b = a.take_and_map('*/bar') { |x| x }
17
+ # b # => ['foo/bar']
18
+ # a # => ['bar']
19
+ #
20
+ # If +flatten_and_compact+ is +true+, the result array will be flattened
21
+ # and compacted. The default is +true+.
22
+ def take_and_map(pattern = nil, flatten_and_compact = true)
23
+ took = []
24
+ reject! do |x|
25
+ next if pattern and !File.fnmatch?(pattern, x)
26
+ if result = yield(x)
27
+ took << result
28
+ end
29
+ end
30
+ if flatten_and_compact
31
+ took.flatten!
32
+ took.compact!
33
+ end
34
+ took
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ Array.send(:include, Kicker::CoreExt::Array)
@@ -0,0 +1,5 @@
1
+ class Kicker
2
+ def self.debug(message)
3
+ $stderr.puts(::Kicker.formatter.call(Time.now, message))
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ class Kicker
2
+ module Deprecated
3
+ def execute(command)
4
+ Kicker.debug("[DEPRECATED] Calling `execute' directly is deprecated, instead use `watcher.execute'. Called from #{_last_caller(caller)}.")
5
+ watcher.execute(command)
6
+ end
7
+
8
+ private
9
+
10
+ def _last_caller(stack)
11
+ stack[0]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ class Kicker
2
+ module Formatter
3
+ def formatters
4
+ @formatters ||= {
5
+ silent: Proc.new {},
6
+ quiet: Proc.new { |time, message| message },
7
+ regular: Proc.new { |time, message| time.strftime('%H:%M:%S.') + time.usec.to_s[0,2] + ' | ' + message }
8
+ }
9
+ end
10
+
11
+ def formatter(name=:regular)
12
+ formatters[name]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ class Kicker
2
+ # Parser for command line options
3
+ class OptionParser
4
+ # Parses ARGV from a Ruby script and returns options and arguments without
5
+ # switch as arrays.
6
+ #
7
+ # OptionParser.parse(%w(create --username manfred -r 1 -r 2)) #=>
8
+ # [[["username", "manfred"], ["r", "1"], ["r", "2"]], ["create"]]
9
+ def self.parse(argv)
10
+ return [[],[]] if argv.empty?
11
+
12
+ options = []
13
+ rest = []
14
+ switch = nil
15
+
16
+ for value in argv
17
+ bytes = value.respond_to?(:bytes) ? value.bytes.first(2) : [value[0], value[1]]
18
+ # value is a switch
19
+ if bytes[0] == 45
20
+ switch = value.slice((bytes[1] == 45 ? 2 : 1)..-1)
21
+ options << [switch]
22
+ else
23
+ if switch
24
+ # we encountered another switch so this
25
+ # value belongs to the last switch
26
+ options[-1] << value
27
+ switch = nil
28
+ else
29
+ rest << value
30
+ end
31
+ end
32
+ end
33
+
34
+ [options, rest]
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,2 @@
1
+ def ignore(expressions)
2
+ end
@@ -0,0 +1,54 @@
1
+ require 'benchmark'
2
+
3
+ class Peck
4
+ attr_reader :cwd, :watcher
5
+
6
+ def initialize(cwd: Dir.pwd, watcher: nil)
7
+ @cwd = cwd
8
+ @watcher = watcher
9
+ end
10
+
11
+ def all_specs
12
+ Dir.glob(File.join(@cwd, 'test/**/*_test.rb'))
13
+ end
14
+
15
+ def peck
16
+ "bundle exec peck"
17
+ end
18
+
19
+ def format_time(seconds)
20
+ if seconds < 1
21
+ "#{(seconds * 1000).round} ms"
22
+ else
23
+ "#{(seconds * 100).round / 100.0} sec"
24
+ end
25
+ end
26
+
27
+ def execute_specs(files)
28
+ return if files.empty?
29
+ realtime = (Benchmark.realtime {
30
+ watcher.execute("#{peck} #{files.join(' ')}")
31
+ })
32
+ watcher.report "Running specs took #{format_time(realtime)}."
33
+ end
34
+
35
+ def map_to_specs(filename)
36
+ Dir.glob(File.join(cwd, "test/**/#{File.basename(filename, '.rb')}_test.rb"))
37
+ end
38
+
39
+ def call(file_or_path, flags)
40
+ ::Kicker.debug("Peck recipe: #{file_or_path}")
41
+ specs = []
42
+ case file_or_path
43
+ when %r{_test\.rb$}
44
+ specs << file_or_path
45
+ when %r{\.rb$}
46
+ specs.concat map_to_specs(file_or_path)
47
+ when %r{\Aapp/views/([\w\\]+)/[^/]+\Z}
48
+ specs.concat map_to_specs($1 + '_controller.rb')
49
+ end
50
+ execute_specs(specs)
51
+ end
52
+ end
53
+
54
+ process(Peck.new(cwd: cwd, watcher: watcher))
File without changes
@@ -1,4 +1,4 @@
1
- class Kicker::Recipes::Ruby
1
+ class Ruby
2
2
  class << self
3
3
  # Assigns the type of tests to run. Eg: `test' or `spec'.
4
4
  attr_writer :test_type
@@ -149,15 +149,15 @@ class Kicker::Recipes::Ruby
149
149
  end
150
150
  end
151
151
 
152
- options.on('-b', '--ruby [PATH]', "Use an alternate Ruby binary for spawned test runners. (Default is `ruby')") do |command|
153
- Kicker::Recipes::Ruby.runner_bin = command
152
+ # Support for Kicker 3.0 recipes
153
+ class Kicker
154
+ class Recipes
155
+ Ruby = Ruby
156
+ end
154
157
  end
155
158
 
156
- recipe :ruby do
157
- process Kicker::Recipes::Ruby
159
+ # options.on('-b', '--ruby [PATH]', "Use an alternate Ruby binary for spawned test runners. (Default is `ruby')") do |command|
160
+ # Kicker::Recipes::Ruby.runner_bin = command
161
+ # end
158
162
 
159
- # When changing the Gemfile, install dependencies
160
- process do |files|
161
- execute 'bundle install' if files.delete('Gemfile')
162
- end
163
- end
163
+ process(Ruby)
@@ -0,0 +1,77 @@
1
+ class Kicker
2
+ class Script
3
+ class Context
4
+ attr_accessor :cwd, :watcher, :script
5
+
6
+ include Kicker::Deprecated
7
+
8
+ def initialize(cwd: Dir.pwd, watcher: nil, script: nil)
9
+ @cwd = cwd
10
+ @watcher = watcher
11
+ @script = script
12
+ end
13
+
14
+ def recipe(name)
15
+ filename = File.join(::Kicker::Script.recipes_path, name.to_s + '.rb')
16
+ if File.exist?(filename)
17
+ ::Kicker.debug("Loading recipe: #{filename}")
18
+ load(filename)
19
+ else
20
+ ::Kicker.debug("Unknown recipe: #{name}")
21
+ end
22
+ end
23
+
24
+ def load(filename)
25
+ eval(File.read(filename), binding, filename)
26
+ end
27
+
28
+ def process(callable=nil, &block)
29
+ processor = callable || block
30
+ ::Kicker.debug("Adding processor: #{processor}")
31
+ script.processors << processor
32
+ end
33
+ end
34
+
35
+ class << self
36
+ attr_accessor :recipes_path
37
+ end
38
+ self.recipes_path = File.expand_path('recipe', __dir__)
39
+
40
+ attr_accessor :cwd, :watcher, :recipes, :processors
41
+
42
+ def initialize(cwd: Dir.pwd, watcher: nil)
43
+ @cwd = cwd
44
+ @watcher = watcher
45
+ @recipes = []
46
+ @processors = []
47
+ @context = Kicker::Script::Context.new(cwd: @cwd, watcher: @watcher, script: self)
48
+ end
49
+
50
+ def recipe(name)
51
+ @context.recipe(name)
52
+ end
53
+
54
+ def load(filename)
55
+ @context.load(filename)
56
+ end
57
+
58
+ def call(file_or_path, flags)
59
+ @processors.each do |processor|
60
+ case processor.method(:call).arity
61
+ when 0
62
+ processor.call
63
+ when 1
64
+ processor.call([file_or_path])
65
+ else
66
+ processor.call(file_or_path, flags)
67
+ end
68
+ end
69
+ end
70
+
71
+ def self.available_recipes
72
+ Dir.glob(File.join(recipes_path, '*.rb')).map do |filename|
73
+ File.basename(filename, '.rb')
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,3 +1,3 @@
1
1
  class Kicker
2
- VERSION = "3.0.0"
3
- end
2
+ VERSION = '4.0.0.p1'
3
+ end
@@ -0,0 +1,113 @@
1
+ require 'pty'
2
+
3
+ class Kicker
4
+ class Watcher
5
+ class << self
6
+ attr_accessor :buffer_size
7
+ end
8
+
9
+ self.buffer_size = 1
10
+
11
+ KICKFILES = %w(Kickfile .kick)
12
+ CLEAR = "\e[H\e[2J"
13
+
14
+ def initialize(options={})
15
+ @options = options
16
+ Kicker.debug("Watcher options: #{@options}")
17
+
18
+ @buffer_size = self.class.buffer_size
19
+
20
+ @out = options[:out] || $stdout
21
+
22
+ @cwd = Dir.pwd
23
+ @script = Script.new(watcher: self, cwd: @cwd)
24
+
25
+ load
26
+ end
27
+
28
+ def load_kickfile
29
+ if @options[:kickfile]
30
+ Kicker.debug("Loading Kickfile from: #{@options[:kickfile]}")
31
+ @script.load(@options[:kickfile])
32
+ true
33
+ else
34
+ false
35
+ end
36
+ end
37
+
38
+ def load_default_kickfile
39
+ loaded = false
40
+ KICKFILES.each do |path|
41
+ kickfile = File.join(@cwd, path)
42
+ if File.exist?(kickfile)
43
+ Kicker.debug("Loading Kickfile from: #{kickfile}")
44
+ @script.load(kickfile)
45
+ loaded = true
46
+ end
47
+ end
48
+ loaded
49
+ end
50
+
51
+ def load_recipes
52
+ @options[:recipes].each do |recipe|
53
+ @script.recipe(recipe)
54
+ end if @options[:recipes]
55
+ end
56
+
57
+ def load
58
+ load_kickfile || load_default_kickfile
59
+ load_recipes
60
+ end
61
+
62
+ def clear_before_execute?
63
+ @options[:clear_before_execute] == true
64
+ end
65
+
66
+ def verbosity
67
+ @options[:verbosity] || :regular
68
+ end
69
+
70
+ def formatter_for_verbosity
71
+ Kicker.formatter(verbosity)
72
+ end
73
+
74
+ def report(message)
75
+ unless verbosity == :silent
76
+ @out.puts(formatter_for_verbosity.call(Time.now, message))
77
+ end
78
+ end
79
+
80
+ def write(buffer)
81
+ @out.write(buffer)
82
+ end
83
+
84
+ def clear
85
+ write(CLEAR)
86
+ end
87
+
88
+ def execute(command)
89
+ clear if clear_before_execute?
90
+ report("Executing: #{command}")
91
+ write("\n") unless verbosity == :silent
92
+ PTY.open do |master, slave|
93
+ read, write = IO.pipe
94
+ pid = spawn(command, in: read, out: slave)
95
+ read.close
96
+ slave.close
97
+ while(buffer = master.read(@buffer_size))
98
+ write(buffer)
99
+ end
100
+ end
101
+ write("\n")
102
+ end
103
+
104
+ def run
105
+ report("Started watching: #{@cwd}")
106
+ Tidings.watch(@cwd) do |file_or_path, flags|
107
+ file_or_path = file_or_path[@cwd.length+1..-1]
108
+ Kicker.debug("Event: #{file_or_path}: #{flags.inspect}")
109
+ @script.call(file_or_path, flags)
110
+ end
111
+ end
112
+ end
113
+ end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kicker
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
5
- prerelease:
4
+ version: 4.0.0.p1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Eloy Duran
@@ -10,105 +9,24 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-12-03 00:00:00.000000000 Z
12
+ date: 2014-04-03 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
- name: listen
15
+ name: tidings
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
- - - ~>
21
- - !ruby/object:Gem::Version
22
- version: 1.3.0
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
- requirements:
28
- - - ~>
29
- - !ruby/object:Gem::Version
30
- version: 1.3.0
31
- - !ruby/object:Gem::Dependency
32
- name: notify
33
- requirement: !ruby/object:Gem::Requirement
34
- none: false
35
- requirements:
36
- - - ~>
37
- - !ruby/object:Gem::Version
38
- version: 0.5.2
39
- type: :runtime
40
- prerelease: false
41
- version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
- requirements:
44
- - - ~>
45
- - !ruby/object:Gem::Version
46
- version: 0.5.2
47
- - !ruby/object:Gem::Dependency
48
- name: bacon
49
- requirement: !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- type: :development
56
- prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
- requirements:
60
- - - ! '>='
61
- - !ruby/object:Gem::Version
62
- version: '0'
63
- - !ruby/object:Gem::Dependency
64
- name: mocha-on-bacon
65
- requirement: !ruby/object:Gem::Requirement
66
- none: false
67
- requirements:
68
- - - ! '>='
69
- - !ruby/object:Gem::Version
70
- version: '0'
71
- type: :development
72
- prerelease: false
73
- version_requirements: !ruby/object:Gem::Requirement
74
- none: false
75
- requirements:
76
- - - ! '>='
77
- - !ruby/object:Gem::Version
78
- version: '0'
79
- - !ruby/object:Gem::Dependency
80
- name: activesupport
81
- requirement: !ruby/object:Gem::Requirement
82
- none: false
83
- requirements:
84
- - - ! '>='
18
+ - - ">="
85
19
  - !ruby/object:Gem::Version
86
20
  version: '0'
87
- type: :development
88
- prerelease: false
89
- version_requirements: !ruby/object:Gem::Requirement
90
- none: false
91
- requirements:
92
- - - ! '>='
93
- - !ruby/object:Gem::Version
94
- version: '0'
95
- - !ruby/object:Gem::Dependency
96
- name: fakefs
97
- requirement: !ruby/object:Gem::Requirement
98
- none: false
99
- requirements:
100
- - - ! '>='
101
- - !ruby/object:Gem::Version
102
- version: '0'
103
- type: :development
21
+ type: :runtime
104
22
  prerelease: false
105
23
  version_requirements: !ruby/object:Gem::Requirement
106
- none: false
107
24
  requirements:
108
- - - ! '>='
25
+ - - ">="
109
26
  - !ruby/object:Gem::Version
110
27
  version: '0'
111
- description: Allows you to fire specific command on file-system change.
28
+ description: Kicker lets you watch filesystem changes and act in them with predefined
29
+ or custom recipes.
112
30
  email:
113
31
  - eloy.de.enige@gmail.com
114
32
  - manfred@fngtps.com
@@ -116,53 +34,47 @@ executables:
116
34
  - kicker
117
35
  extensions: []
118
36
  extra_rdoc_files:
119
- - LICENSE
37
+ - COPYING
120
38
  - README.rdoc
121
39
  files:
40
+ - COPYING
41
+ - README.rdoc
122
42
  - bin/kicker
123
- - lib/kicker/callback_chain.rb
124
- - lib/kicker/core_ext.rb
125
- - lib/kicker/fsevents.rb
126
- - lib/kicker/job.rb
127
- - lib/kicker/notification.rb
128
- - lib/kicker/options.rb
129
- - lib/kicker/recipes/could_not_handle_file.rb
130
- - lib/kicker/recipes/dot_kick.rb
131
- - lib/kicker/recipes/execute_cli_command.rb
132
- - lib/kicker/recipes/ignore.rb
133
- - lib/kicker/recipes/jstest.rb
134
- - lib/kicker/recipes/rails.rb
135
- - lib/kicker/recipes/ruby.rb
136
- - lib/kicker/recipes.rb
137
- - lib/kicker/utils.rb
138
- - lib/kicker/version.rb
139
43
  - lib/kicker.rb
140
- - README.rdoc
141
- - LICENSE
142
- homepage: http://github.com/alloy/kicker
143
- licenses:
144
- - MIT
44
+ - lib/kicker/cli.rb
45
+ - lib/kicker/core_ext/array.rb
46
+ - lib/kicker/debug.rb
47
+ - lib/kicker/deprecated.rb
48
+ - lib/kicker/formatter.rb
49
+ - lib/kicker/option_parser.rb
50
+ - lib/kicker/recipe/ignore.rb
51
+ - lib/kicker/recipe/peck.rb
52
+ - lib/kicker/recipe/reload.rb
53
+ - lib/kicker/recipe/ruby.rb
54
+ - lib/kicker/script.rb
55
+ - lib/kicker/version.rb
56
+ - lib/kicker/watcher.rb
57
+ homepage: http://github.com/Manfred/kicker
58
+ licenses: []
59
+ metadata: {}
145
60
  post_install_message:
146
61
  rdoc_options: []
147
62
  require_paths:
148
63
  - lib
149
- - vendor
150
64
  required_ruby_version: !ruby/object:Gem::Requirement
151
- none: false
152
65
  requirements:
153
- - - ! '>='
66
+ - - ">="
154
67
  - !ruby/object:Gem::Version
155
68
  version: '0'
156
69
  required_rubygems_version: !ruby/object:Gem::Requirement
157
- none: false
158
70
  requirements:
159
- - - ! '>='
71
+ - - ">"
160
72
  - !ruby/object:Gem::Version
161
- version: '0'
73
+ version: 1.3.1
162
74
  requirements: []
163
75
  rubyforge_project:
164
- rubygems_version: 1.8.23
76
+ rubygems_version: 2.2.2
165
77
  signing_key:
166
- specification_version: 3
78
+ specification_version: 4
167
79
  summary: A lean, agnostic, flexible file-change watcher.
168
80
  test_files: []