spicycode-beholder 0.0.2
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/LICENSE +20 -0
- data/README.textile +13 -0
- data/Rakefile +68 -0
- data/TODO +1 -0
- data/bin/beholder +4 -0
- data/examples/example_helper.rb +18 -0
- data/examples/lib/beholder_example.rb +89 -0
- data/lib/beholder.rb +89 -0
- metadata +71 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008-2009 Chad Humphries
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rubygems/specification'
|
4
|
+
require 'date'
|
5
|
+
require 'micronaut/rake_task'
|
6
|
+
|
7
|
+
GEM = "beholder"
|
8
|
+
GEM_VERSION = "0.0.2"
|
9
|
+
AUTHOR = "Chad Humphries"
|
10
|
+
EMAIL = "chad@spicycode.com"
|
11
|
+
HOMEPAGE = "http://github.com/spicycode/beholder"
|
12
|
+
SUMMARY = "An ancient beholder that watches your treasure, and deals with thiefs"
|
13
|
+
|
14
|
+
spec = Gem::Specification.new do |s|
|
15
|
+
s.name = GEM
|
16
|
+
s.version = GEM_VERSION
|
17
|
+
s.platform = Gem::Platform::RUBY
|
18
|
+
s.has_rdoc = true
|
19
|
+
s.extra_rdoc_files = ["README.textile", "LICENSE", 'TODO']
|
20
|
+
s.summary = SUMMARY
|
21
|
+
s.description = s.summary
|
22
|
+
s.author = AUTHOR
|
23
|
+
s.email = EMAIL
|
24
|
+
s.homepage = HOMEPAGE
|
25
|
+
|
26
|
+
# Uncomment this to add a dependency
|
27
|
+
s.add_dependency "fsevents"
|
28
|
+
s.bindir = 'bin'
|
29
|
+
s.default_executable = 'beholder'
|
30
|
+
s.executables = ["beholder"]
|
31
|
+
s.require_path = 'lib'
|
32
|
+
s.autorequire = GEM
|
33
|
+
s.files = %w(LICENSE README.textile Rakefile TODO) + Dir.glob("{lib,examples}/**/*")
|
34
|
+
end
|
35
|
+
|
36
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
37
|
+
pkg.gem_spec = spec
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "install the gem locally"
|
41
|
+
task :install => [:package] do
|
42
|
+
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "create a gemspec file"
|
46
|
+
task :make_gemspec do
|
47
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
48
|
+
file.puts spec.to_ruby
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Run all micronaut examples"
|
53
|
+
Micronaut::RakeTask.new :examples do |t|
|
54
|
+
t.pattern = "examples/**/*_example.rb"
|
55
|
+
end
|
56
|
+
|
57
|
+
namespace :examples do
|
58
|
+
|
59
|
+
desc "Run all micronaut examples using rcov"
|
60
|
+
Micronaut::RakeTask.new :coverage do |t|
|
61
|
+
t.pattern = "examples/**/*_example.rb"
|
62
|
+
t.rcov = true
|
63
|
+
t.rcov_opts = "--exclude \"examples/*,gems/*,db/*,/Library/Frameworks/*,/Library/Ruby/*,config/*\" --text-summary --sort coverage --no-validator-links"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
task :default => 'examples:coverage'
|
data/bin/beholder
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
lib_path = File.expand_path(File.dirname(__FILE__) + "/../lib")
|
2
|
+
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
|
3
|
+
|
4
|
+
require 'beholder'
|
5
|
+
require 'rubygems'
|
6
|
+
require 'micronaut'
|
7
|
+
gem :rr, '=0.7.0'
|
8
|
+
|
9
|
+
|
10
|
+
def not_in_editor?
|
11
|
+
['TM_MODE', 'EMACS', 'VIM'].all? { |k| !ENV.has_key?(k) }
|
12
|
+
end
|
13
|
+
|
14
|
+
Micronaut.configure do |c|
|
15
|
+
c.formatter = :documentation
|
16
|
+
c.mock_with :rr
|
17
|
+
c.color_enabled = not_in_editor?
|
18
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../example_helper")
|
2
|
+
|
3
|
+
describe Beholder do
|
4
|
+
|
5
|
+
describe "when casting it's gaze" do
|
6
|
+
|
7
|
+
it "should begat a new beholder" do
|
8
|
+
beholder = stub(Beholder.new) { prepare_for_interlopers; open_your_eye }
|
9
|
+
mock(Beholder).new { beholder }
|
10
|
+
Beholder.cast_thy_gaze
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should prepare the child for interlopers" do
|
14
|
+
beholder = Beholder.new
|
15
|
+
stub(beholder).open_your_eye
|
16
|
+
mock(beholder).prepare_for_interlopers
|
17
|
+
stub(Beholder).new { beholder }
|
18
|
+
|
19
|
+
Beholder.cast_thy_gaze
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should open the child's eyes" do
|
23
|
+
beholder = Beholder.new
|
24
|
+
mock(beholder).open_your_eye
|
25
|
+
stub(beholder).prepare_for_interlopers
|
26
|
+
stub(Beholder).new { beholder }
|
27
|
+
|
28
|
+
Beholder.cast_thy_gaze
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "when it notices a thief taking treasure" do
|
34
|
+
|
35
|
+
it "should howl about the theft" do
|
36
|
+
beholder = Beholder.new
|
37
|
+
mock(beholder).say "#{[]} changed"
|
38
|
+
beholder.notice_thief_taking []
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should identify what was stolen" do
|
42
|
+
treasures = ['pot_o_gold']
|
43
|
+
beholder = Beholder.new
|
44
|
+
mock(beholder).identify_stolen_treasure('pot_o_gold') { nil }
|
45
|
+
beholder.notice_thief_taking treasures
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should reclaim the stolen treasures" do
|
49
|
+
treasures = ['pot_o_gold']
|
50
|
+
beholder = Beholder.new
|
51
|
+
stub(beholder).identify_stolen_treasure('pot_o_gold') { 'x marks the spot' }
|
52
|
+
mock(beholder).reclaim_stolen_treasure_at(['x marks the spot'])
|
53
|
+
beholder.notice_thief_taking treasures
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "when blinking it's eye" do
|
59
|
+
|
60
|
+
it "should forget about any interlopers" do
|
61
|
+
beholder = Beholder.new
|
62
|
+
beholder.instance_variable_set("@sent_an_int", true) # Not so hot, but I'm tired
|
63
|
+
|
64
|
+
beholder.sent_an_int.should be_true
|
65
|
+
beholder.blink
|
66
|
+
beholder.sent_an_int.should be_false
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "when closing it's eye" do
|
72
|
+
|
73
|
+
it "should stop watching for interlopers" do
|
74
|
+
beholder = Beholder.new
|
75
|
+
stub(beholder).exit
|
76
|
+
stub(beholder).the_eye { mock!.shutdown }
|
77
|
+
beholder.close_your_eye
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should leave the dungeon" do
|
81
|
+
beholder = Beholder.new
|
82
|
+
stub(beholder).the_eye { stub!.shutdown }
|
83
|
+
mock(beholder).exit
|
84
|
+
beholder.close_your_eye
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
data/lib/beholder.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem :fsevents
|
3
|
+
require 'fsevents'
|
4
|
+
|
5
|
+
class Beholder
|
6
|
+
|
7
|
+
attr_reader :paths_to_watch, :sent_an_int, :mappings, :working_directory, :be_verbose, :the_eye
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@paths_to_watch = ['app', 'config', 'lib', 'examples']
|
11
|
+
@sent_an_int = false
|
12
|
+
@mappings = {}
|
13
|
+
@working_directory = Dir.pwd
|
14
|
+
@be_verbose = ARGV.include?("-v") || ARGV.include?("--verbose")
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.cast_thy_gaze
|
18
|
+
@beholder = new
|
19
|
+
@beholder.prepare_for_interlopers
|
20
|
+
@beholder.open_your_eye
|
21
|
+
end
|
22
|
+
|
23
|
+
def open_your_eye
|
24
|
+
say("Watching the following locations:\n #{paths_to_watch.join(", ")}")
|
25
|
+
@the_eye = FSEvents::Stream.watch(paths_to_watch) do |treasure_chest|
|
26
|
+
notice_thief_taking(treasure_chest.modified_files)
|
27
|
+
blink
|
28
|
+
puts "\n\nWaiting to hear from the disk since #{Time.now}"
|
29
|
+
end
|
30
|
+
@the_eye.run
|
31
|
+
end
|
32
|
+
|
33
|
+
def blink
|
34
|
+
@sent_an_int = false
|
35
|
+
end
|
36
|
+
|
37
|
+
def close_your_eye
|
38
|
+
the_eye.shutdown
|
39
|
+
exit
|
40
|
+
end
|
41
|
+
|
42
|
+
def identify_stolen_treasure(treasure)
|
43
|
+
case treasure
|
44
|
+
when /#{working_directory}\/app\/(.*)\.rb/
|
45
|
+
"examples/#{$1}_example.rb"
|
46
|
+
when /#{working_directory}\/lib\/(.*)\.rb/
|
47
|
+
"examples/lib/#{$1}_example.rb"
|
48
|
+
when /#{working_directory}\/examples\/(.*)_example\.rb/
|
49
|
+
"examples/#{$1}_example.rb"
|
50
|
+
when /#{working_directory}\/examples\/example_helper\.rb/,
|
51
|
+
/#{working_directory}\/config/
|
52
|
+
"examples/**/*_example.rb"
|
53
|
+
else
|
54
|
+
say "Unknown file: #{treasure}"
|
55
|
+
''
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def reclaim_stolen_treasure_at(coordinates)
|
60
|
+
return if coordinates.nil? || coordinates.empty?
|
61
|
+
puts "\nRunning #{coordinates.join(', ')}"
|
62
|
+
system "ruby #{coordinates.map { |f| Dir.glob(f) }.join(' ')}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def notice_thief_taking(treasure)
|
66
|
+
say "#{treasure} changed"
|
67
|
+
coordinates = treasure.map { |t| identify_stolen_treasure(t) }.uniq.compact
|
68
|
+
reclaim_stolen_treasure_at coordinates
|
69
|
+
end
|
70
|
+
|
71
|
+
def prepare_for_interlopers
|
72
|
+
trap 'INT' do
|
73
|
+
if @sent_an_int then
|
74
|
+
puts " A second INT? Ok, I get the message. Shutting down now."
|
75
|
+
close_your_eye
|
76
|
+
else
|
77
|
+
puts " Did you just send me an INT? Ugh. I'll quit for real if you do it again."
|
78
|
+
@sent_an_int = true
|
79
|
+
Kernel.sleep 1.5
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def say(this_message_please)
|
86
|
+
puts this_message_please if be_verbose
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spicycode-beholder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chad Humphries
|
8
|
+
autorequire: beholder
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-05 00:00:00 -08:00
|
13
|
+
default_executable: beholder
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: fsevents
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
description: An ancient beholder that watches your treasure, and deals with thiefs
|
25
|
+
email: chad@spicycode.com
|
26
|
+
executables:
|
27
|
+
- beholder
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README.textile
|
32
|
+
- LICENSE
|
33
|
+
- TODO
|
34
|
+
files:
|
35
|
+
- LICENSE
|
36
|
+
- README.textile
|
37
|
+
- Rakefile
|
38
|
+
- TODO
|
39
|
+
- lib/beholder.rb
|
40
|
+
- examples/example_helper.rb
|
41
|
+
- examples/lib
|
42
|
+
- examples/lib/beholder_example.rb
|
43
|
+
- bin/beholder
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/spicycode/beholder
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.2.0
|
67
|
+
signing_key:
|
68
|
+
specification_version: 2
|
69
|
+
summary: An ancient beholder that watches your treasure, and deals with thiefs
|
70
|
+
test_files: []
|
71
|
+
|