visionmedia-bind 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+
2
+ === 0.0.1 / 2009-03-03
3
+
4
+ * Initial release
@@ -0,0 +1,23 @@
1
+ bin/bind
2
+ bind.gemspec
3
+ examples/demo.html
4
+ examples/log_changes.rb
5
+ examples/refresh_browsers.rb
6
+ examples/style.css
7
+ History.rdoc
8
+ lib/bind/actions/refresh_browsers.rb
9
+ lib/bind/actions.rb
10
+ lib/bind/command_helpers.rb
11
+ lib/bind/listener.rb
12
+ lib/bind/version.rb
13
+ lib/bind.rb
14
+ Manifest
15
+ Rakefile
16
+ README.rdoc
17
+ spec/bind_listener_spec.rb
18
+ spec/fixtures/style.css
19
+ spec/spec_helper.rb
20
+ tasks/docs.rake
21
+ tasks/gemspec.rake
22
+ tasks/spec.rake
23
+ Todo.rdoc
@@ -0,0 +1,36 @@
1
+
2
+ = Bind
3
+
4
+ Bind actions to various file system events, helping aid in
5
+ automation of tasks such as refreshing browser(s) when you
6
+ update a css / sass / js file.
7
+
8
+ == Features
9
+
10
+ * Coming soon
11
+
12
+ == License:
13
+
14
+ (The MIT License)
15
+
16
+ Copyright (c) 2009 TJ Holowaychuk <tj@vision-media.ca>
17
+
18
+ Permission is hereby granted, free of charge, to any person obtaining
19
+ a copy of this software and associated documentation files (the
20
+ 'Software'), to deal in the Software without restriction, including
21
+ without limitation the rights to use, copy, modify, merge, publish,
22
+ distribute, sublicense, an d/or sell copies of the Software, and to
23
+ permit persons to whom the Software is furnished to do so, subject to
24
+ the following conditions:
25
+
26
+ The above copyright notice and this permission notice shall be
27
+ included in all copies or substantial portions of the Software.
28
+
29
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
30
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
33
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
34
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
35
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36
+ GS IN THE SOFTWARE.
@@ -0,0 +1,16 @@
1
+
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'echoe'
5
+ require './lib/bind.rb'
6
+
7
+ Echoe.new("bind", Bind::VERSION::STRING) do |p|
8
+ p.author = "TJ Holowaychuk"
9
+ p.email = "tj@vision-media.ca"
10
+ p.summary = "bind actions to filesystem events"
11
+ p.url = "http://github.com/visionmedia/bind"
12
+ p.runtime_dependencies = []
13
+ p.runtime_dependencies << 'visionmedia-commander >=2.4.6'
14
+ end
15
+
16
+ Dir['tasks/**/*.rake'].sort.each { |lib| load lib }
@@ -0,0 +1,13 @@
1
+
2
+ == Major:
3
+
4
+ * Add support for an eval BEFORE actions, such as building SASS / HAML
5
+
6
+ == Minor:
7
+
8
+ * Support action / event pairs, n to n, not 1 to 1
9
+ * Add more actions / events like atime
10
+
11
+ == Brainstorming:
12
+
13
+ * Nothing
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bind'
5
+ require 'bind/command_helpers'
6
+ require 'commander'
7
+
8
+ program :name, 'Bind'
9
+ program :version, Bind::VERSION::STRING
10
+ program :description, 'Bind actions to filesystem events'
11
+
12
+ command :to do |c|
13
+ set_common_options c
14
+ c.syntax = 'bind to <file> [file ...] [options] '
15
+ c.summary = 'Bind to modification of a file'
16
+ c.description = 'Bind to modification of a file or all files within a directory.'
17
+ c.example 'Bind to a single file, logging its path when changed', "bind change style.css -e 'puts file'"
18
+ c.option '-e', '--eval STRING', String, 'Evaluate a string of Ruby in context of Bind, so the file local variable is available.'
19
+ c.when_called do |args, options|
20
+ populate_common_options options
21
+ if options.eval
22
+ options.action = lambda { |file| eval options.eval }
23
+ else
24
+ abort 'invalid option. --eval switch is required in order to perform any action on the bound file(s)'
25
+ end
26
+ options.files = args
27
+ listener(options).run!
28
+ end
29
+ end
30
+
31
+ command :refresh do |c|
32
+ set_common_options c
33
+ c.syntax = 'bind refresh <uri> [options]'
34
+ c.summary = 'Bind to <uri>, refreshing browsers.'
35
+ c.description = 'Bind to <uri>, refreshing browsers when the files you are watching change.'
36
+ c.example = 'Bind a few css files for quick editing in multiple browsers', 'bind refresh http://localhost/page --files style.css,reset.css --browsers Safari,Firefox'
37
+ c.example = 'Bind local static html (no scheme)', 'bind refresh examples/demo.html -f style.css -b Safari'
38
+ c.option '-b', '--browsers BROWSERS', Array, 'List of browsers you wish to refresh. Defaults to Safari'
39
+ c.option '-f', '--files FILES', Array, 'List of files to bind to.'
40
+ c.when_called do |args, options|
41
+ populate_common_options options
42
+ path = expand_path args.shift
43
+ browsers = options.browsers || ['Safari']
44
+ options.action = Bind::Actions::RefreshBrowsers.new path, *browsers
45
+ abort 'invalid option. --files switch is required in order to bind' if options.files.nil?
46
+ listener(options).run!
47
+ end
48
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{bind}
5
+ s.version = "0.0.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["TJ Holowaychuk"]
9
+ s.date = %q{2009-03-03}
10
+ s.default_executable = %q{bind}
11
+ s.description = %q{bind actions to filesystem events}
12
+ s.email = %q{tj@vision-media.ca}
13
+ s.executables = ["bind"]
14
+ s.extra_rdoc_files = ["bin/bind", "bind.gemspec", "lib/bind/actions/refresh_browsers.rb", "lib/bind/actions.rb", "lib/bind/command_helpers.rb", "lib/bind/listener.rb", "lib/bind/version.rb", "lib/bind.rb", "README.rdoc", "tasks/docs.rake", "tasks/gemspec.rake", "tasks/spec.rake"]
15
+ s.files = ["bin/bind", "bind.gemspec", "examples/demo.html", "examples/log_changes.rb", "examples/refresh_browsers.rb", "examples/style.css", "History.rdoc", "lib/bind/actions/refresh_browsers.rb", "lib/bind/actions.rb", "lib/bind/command_helpers.rb", "lib/bind/listener.rb", "lib/bind/version.rb", "lib/bind.rb", "Manifest", "Rakefile", "README.rdoc", "spec/bind_listener_spec.rb", "spec/fixtures/style.css", "spec/spec_helper.rb", "tasks/docs.rake", "tasks/gemspec.rake", "tasks/spec.rake", "Todo.rdoc"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://github.com/visionmedia/bind}
18
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Bind", "--main", "README.rdoc"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{bind}
21
+ s.rubygems_version = %q{1.3.1}
22
+ s.summary = %q{bind actions to filesystem events}
23
+
24
+ if s.respond_to? :specification_version then
25
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
26
+ s.specification_version = 2
27
+
28
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
29
+ s.add_runtime_dependency(%q<visionmedia-commander>, [">= 2.4.6"])
30
+ else
31
+ s.add_dependency(%q<visionmedia-commander>, [">= 2.4.6"])
32
+ end
33
+ else
34
+ s.add_dependency(%q<visionmedia-commander>, [">= 2.4.6"])
35
+ end
36
+ end
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <body>
3
+ <title>Bind Demo</title>
4
+ <link rel="stylesheet" href="style.css" />
5
+ </body>
6
+ <h1>Bind Demo</h1>
7
+ <p>Try binding to style.css and editing it, then watch bind update several browsers simaltaniously.</p>
8
+ </html>
@@ -0,0 +1,9 @@
1
+
2
+ require File.dirname(__FILE__) + '/../lib/bind'
3
+
4
+ # Execute this file to start the listener, then alter style.css a few times
5
+
6
+ style = File.dirname(__FILE__) + '/style.css'
7
+ action = lambda { |file| puts "modified #{file}" }
8
+ listener = Bind::Listener.new :event => :change, :files => [style], :interval => 1, :action => action, :timeout => 10, :log => $stdout
9
+ listener.run!
@@ -0,0 +1,10 @@
1
+
2
+ require File.dirname(__FILE__) + '/../lib/bind'
3
+
4
+ # Execute this file to start the listener, then alter style.css a few times
5
+
6
+ html = File.expand_path(File.dirname(__FILE__) + '/demo.html')
7
+ style = File.dirname(__FILE__) + '/style.css'
8
+ action = Bind::Actions::RefreshBrowsers.new html, 'Safari', 'Firefox'
9
+ listener = Bind::Listener.new :event => :change, :files => [style], :interval => 1, :action => action, :timeout => 60, :log => $stdout
10
+ listener.run!
@@ -0,0 +1,3 @@
1
+ h1 {
2
+ color: blue;
3
+ }
@@ -0,0 +1,28 @@
1
+ #--
2
+ # Copyright (c) 2009 TJ Holowaychuk <tj@vision-media.ca>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ $:.unshift File.dirname(__FILE__)
25
+
26
+ require 'bind/version'
27
+ require 'bind/listener'
28
+ require 'bind/actions'
@@ -0,0 +1,6 @@
1
+
2
+ module Bind
3
+ module Actions
4
+ autoload :RefreshBrowsers, 'bind/actions/refresh_browsers'
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+
2
+ module Bind
3
+ module Actions
4
+ class RefreshBrowsers
5
+
6
+ attr_accessor :browsers, :uri
7
+
8
+ def initialize uri, *browsers
9
+ @uri, @browsers = uri, browsers
10
+ end
11
+
12
+ def call file
13
+ @browsers.each { |browser| `open -g -a #{browser} #{uri}` }
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+
2
+ def set_common_options c
3
+ c.option '-i', '--interval SECONDS', Integer, 'Interval in seconds in which to listen for an event.'
4
+ c.option '-t', '--timeout SECONDS', Integer, 'Timeout after n seconds.'
5
+ c.option '-r', '--require LIBS', Array, 'Require ruby libraries.'
6
+ c.option '-V', '--verbose', 'Log information to STDOUT.'
7
+ end
8
+
9
+ def listener options
10
+ Bind::Listener.new options_to_hash(options)
11
+ end
12
+
13
+ def populate_common_options options
14
+ options.require.each { |lib| require lib } if options.require
15
+ options.debug = $stdout if options.verbose
16
+ end
17
+
18
+ def expand_path path
19
+ path.include?('://') ? path : File.expand_path(path)
20
+ end
21
+
22
+ def options_to_hash options
23
+ options.singleton_methods.inject({}) do |hash, meth|
24
+ hash[meth.to_sym] = options.send meth unless meth =~ /=$/
25
+ hash
26
+ end
27
+ end
@@ -0,0 +1,93 @@
1
+
2
+
3
+ module Bind
4
+ class Listener
5
+
6
+ attr_accessor :files, :action, :timeout, :interval, :event
7
+ attr_reader :run_time, :start_time, :finish_time
8
+
9
+ #--
10
+ # Exceptions
11
+ #++
12
+
13
+ class Error < StandardError; end
14
+
15
+ ##
16
+ # Event listener. Must specify the :files, and :action options.
17
+ #
18
+ # === Options:
19
+ #
20
+ # :files array of files and / or directories
21
+ # :action an object responding to #call, which is used as the callback for the event handler
22
+ # :timeout time in seconds, after which the listener should stop. Defaults to 0, meaning infinity
23
+ # :event event to bind to, may be one of (:change). Defaults to :change
24
+ # :debug log verbose debugging information to this stream
25
+ # :interval sleep interval in seconds. Defaults to 2
26
+ #
27
+
28
+ def initialize options = {}
29
+ @run_time, @mtimes = 0, {}
30
+ @files = options.fetch :files do
31
+ raise ArgumentError, 'specify one or more :files (or directories) to bind the listener to'
32
+ end
33
+ @action = options.fetch :action do
34
+ raise ArgumentError, 'pass a valid :action responding to #call'
35
+ end
36
+ @log = options.fetch :debug, false
37
+ @timeout = options.fetch :timeout, 0
38
+ @interval = options.fetch :interval, 2
39
+ @event = options.fetch :event, :change
40
+ end
41
+
42
+ ##
43
+ # Start the listener.
44
+
45
+ def run!
46
+ start_time = Time.now
47
+ log "binding to #{files.join(', ')}, watching #{event} every #{interval} second(s)." +
48
+ (timeout > 0 ? " Terminating in #{timeout} seconds" : '')
49
+ catch :halt do
50
+ loop do
51
+ @run_time = Time.now - start_time
52
+ throw :halt if timeout > 0 and @run_time >= timeout
53
+ log '.', true
54
+ files.each { |file| send event, File.new(file) }
55
+ sleep interval
56
+ end
57
+ end
58
+ finish_time = Time.now
59
+ log "binding terminated"
60
+ end
61
+
62
+ private
63
+
64
+ ##
65
+ # Handle change event.
66
+
67
+ def change file
68
+ if changed? file
69
+ log "changed #{file.path}"
70
+ action.call file
71
+ @mtimes[file.path] = file.mtime
72
+ end
73
+ end
74
+
75
+ ##
76
+ # Check if +file+ has been modified since the last check.
77
+
78
+ def changed? file
79
+ file.mtime > (@mtimes[file.path] ||= file.mtime)
80
+ end
81
+
82
+ ##
83
+ # Optionally log a +message+ when a stream has been specified.
84
+
85
+ def log message, print = false
86
+ if @log
87
+ print ? @log.print(message) : @log.puts(message)
88
+ @log.flush
89
+ end
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,7 @@
1
+
2
+ module Bind
3
+ module VERSION #:nodoc:
4
+ MAJOR, MINOR, TINY = 0, 0, 2
5
+ STRING = [MAJOR, MINOR, TINY].join '.'
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+
2
+ describe Bind::Listener do
3
+
4
+ def listener &action
5
+ Bind::Listener.new :event => :change, :files => [File.dirname(__FILE__) + '/fixtures/style.css'], :interval => 1, :action => action, :timeout => 2
6
+ end
7
+
8
+ it "should record total runtime" do
9
+ l = listener {}
10
+ l.run!
11
+ l.run_time.to_i.should == 2
12
+ end
13
+
14
+ end
File without changes
@@ -0,0 +1,2 @@
1
+
2
+ require 'bind'
@@ -0,0 +1,13 @@
1
+
2
+ namespace :docs do
3
+
4
+ desc 'Remove rdoc products'
5
+ task :remove => [:clobber_docs]
6
+
7
+ desc 'Build docs, and open in browser for viewing (specify BROWSER)'
8
+ task :open do
9
+ browser = ENV["BROWSER"] || "safari"
10
+ sh "open -a #{browser} doc/index.html"
11
+ end
12
+
13
+ end
@@ -0,0 +1,3 @@
1
+
2
+ desc 'Build gemspec file'
3
+ task :gemspec => [:build_gemspec]
@@ -0,0 +1,25 @@
1
+
2
+ require 'spec/rake/spectask'
3
+
4
+ desc "Run all specifications"
5
+ Spec::Rake::SpecTask.new(:spec) do |t|
6
+ t.libs << "lib"
7
+ t.spec_opts = ["--color", "--require", "spec/spec_helper.rb"]
8
+ end
9
+
10
+ namespace :spec do
11
+
12
+ desc "Run all specifications verbosely"
13
+ Spec::Rake::SpecTask.new(:verbose) do |t|
14
+ t.libs << "lib"
15
+ t.spec_opts = ["--color", "--format", "specdoc", "--require", "spec/spec_helper.rb"]
16
+ end
17
+
18
+ desc "Run specific specification verbosely (specify SPEC)"
19
+ Spec::Rake::SpecTask.new(:select) do |t|
20
+ t.libs << "lib"
21
+ t.spec_files = [ENV["SPEC"]]
22
+ t.spec_opts = ["--color", "--format", "specdoc", "--require", "spec/spec_helper.rb"]
23
+ end
24
+
25
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: visionmedia-bind
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - TJ Holowaychuk
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-03 00:00:00 -08:00
13
+ default_executable: bind
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: visionmedia-commander
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.4.6
24
+ version:
25
+ description: bind actions to filesystem events
26
+ email: tj@vision-media.ca
27
+ executables:
28
+ - bind
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - bin/bind
33
+ - bind.gemspec
34
+ - lib/bind/actions/refresh_browsers.rb
35
+ - lib/bind/actions.rb
36
+ - lib/bind/command_helpers.rb
37
+ - lib/bind/listener.rb
38
+ - lib/bind/version.rb
39
+ - lib/bind.rb
40
+ - README.rdoc
41
+ - tasks/docs.rake
42
+ - tasks/gemspec.rake
43
+ - tasks/spec.rake
44
+ files:
45
+ - bin/bind
46
+ - bind.gemspec
47
+ - examples/demo.html
48
+ - examples/log_changes.rb
49
+ - examples/refresh_browsers.rb
50
+ - examples/style.css
51
+ - History.rdoc
52
+ - lib/bind/actions/refresh_browsers.rb
53
+ - lib/bind/actions.rb
54
+ - lib/bind/command_helpers.rb
55
+ - lib/bind/listener.rb
56
+ - lib/bind/version.rb
57
+ - lib/bind.rb
58
+ - Manifest
59
+ - Rakefile
60
+ - README.rdoc
61
+ - spec/bind_listener_spec.rb
62
+ - spec/fixtures/style.css
63
+ - spec/spec_helper.rb
64
+ - tasks/docs.rake
65
+ - tasks/gemspec.rake
66
+ - tasks/spec.rake
67
+ - Todo.rdoc
68
+ has_rdoc: true
69
+ homepage: http://github.com/visionmedia/bind
70
+ post_install_message:
71
+ rdoc_options:
72
+ - --line-numbers
73
+ - --inline-source
74
+ - --title
75
+ - Bind
76
+ - --main
77
+ - README.rdoc
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "1.2"
91
+ version:
92
+ requirements: []
93
+
94
+ rubyforge_project: bind
95
+ rubygems_version: 1.2.0
96
+ signing_key:
97
+ specification_version: 2
98
+ summary: bind actions to filesystem events
99
+ test_files: []
100
+