jsrebuild 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.
@@ -0,0 +1,4 @@
1
+ doc
2
+ test/build
3
+ Gemfile.lock
4
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ === 1.0.0 / 2011-08-12
4
+
5
+ * Initial release.
data/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ Copyright (c) 2011, the OTHER media.
2
+
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright notice,
9
+ this list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ * Neither the name of the OTHER media nor the names of other contributors
16
+ may be used to endorse or promote products derived from this software
17
+ without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,55 @@
1
+ jsrebuild
2
+ =========
3
+
4
+ **jsrebuild** dynamically runs the [Jake] build tool to rebuild JavaScript
5
+ projects in development environments.
6
+
7
+ [Jake]: https://github.com/jcoglan/jake
8
+
9
+ Overview
10
+ --------
11
+
12
+ Jake is often run as part of a website's build process, building JavaScript
13
+ packages from source files. This often leads to a tedious situation for
14
+ projects which use Jake, as the developer must continually run the `jake`
15
+ command to rebuild their JavaScript files as they make changes to the source
16
+ code.
17
+
18
+ The `jsrebuild` utility provides a solution to this problem: it watches a
19
+ source directory and rebuilds the project whenever changes are made to the
20
+ source files, `jake.yml` config file and the `Jakefile` helper file.
21
+
22
+
23
+ Installation
24
+ ------------
25
+
26
+ jsrebuild uses the [Cool.io] library which depends on [libev], a low-level
27
+ event loop library, so you will need to have libev installed before attempting
28
+ to install the jsrebuild gem.
29
+
30
+ jsrebuild is available from RubyGems, so you can install it and its
31
+ dependencies simply by running
32
+
33
+ gem install jsrebuild
34
+
35
+ [cool.io]: https://github.com/tarcieri/cool.io
36
+ [libev]: http://software.schmorp.de/pkg/libev.html
37
+
38
+
39
+ Running `jsrebuild`
40
+ -------------------
41
+
42
+ To watch a particular directory such as `~/projects/mywebapp` for changes, just
43
+ run
44
+
45
+ jsrebuild ~/projects/mywebapp
46
+
47
+ The `jsrebuild` tool takes a number of command-line arguments, allowing you to
48
+ set options such as the interval at which it checks files for changes, and
49
+ whether or not to force all the project's packages to be rebuild whenever a
50
+ change is made.
51
+
52
+ For a full list of options, run `jsrebuild --help`.
53
+
54
+ `jsrebuild` will happily run daemonised. To shut down the process, simply send
55
+ it `SIGHUP` and it will shut down the event loop and exit cleanly.
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.dirname(__FILE__) + '/../lib'
4
+ $:.unshift(lib) unless $:.include?(lib)
5
+
6
+ require 'oyster'
7
+ require 'jsrebuild'
8
+
9
+ spec = Oyster.spec do
10
+ name "jsrebuild -- dynamic rebuilder for JavaScript projects"
11
+
12
+ synopsis <<-EOS
13
+ jsrebuild [--force] [--interval TIME] [DIR]
14
+ EOS
15
+
16
+ description <<-EOS
17
+ Dynamically runs the Jake build tool to rebuild JavaScript
18
+ projects in development environments.
19
+ EOS
20
+
21
+ flag :force, :default => false,
22
+ :desc => "Force a rebuild of all files when any change is made"
23
+
24
+ float :interval, :default => 0.5,
25
+ :desc => <<-EOS
26
+ Set the frequency (in seconds) with which files are checked for
27
+ modifications.
28
+ EOS
29
+
30
+ author "Benedict Eastaugh <benedict@eastaugh.net>"
31
+ end
32
+
33
+ begin
34
+ opts = spec.parse
35
+ rescue Oyster::HelpRendered
36
+ exit(true)
37
+ end
38
+
39
+ dir = File.expand_path(opts[:unclaimed].first || '.')
40
+ interval = opts[:interval]
41
+ jake_options = {
42
+ :force => opts[:force]
43
+ }
44
+
45
+ unless File.directory?(dir)
46
+ $stderr.puts "Directory \"#{dir}\" does not exist"
47
+ exit(false)
48
+ end
49
+
50
+
51
+ unless File.readable?(dir)
52
+ $stderr.puts "Directory \"#{dir}\" is not readable"
53
+ exit(false)
54
+ end
55
+
56
+ runner = JSRebuild::Runner.new(dir, interval, jake_options)
57
+ runner.run!
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env gem build
2
+ # encoding: utf-8
3
+
4
+ lib = File.expand_path('../lib/', __FILE__)
5
+ $:.unshift lib unless $:.include?(lib)
6
+
7
+ require 'jsrebuild/version'
8
+
9
+ Gem::Specification.new do |gem|
10
+ gem.name = "jsrebuild"
11
+ gem.version = JSRebuild::VERSION
12
+ gem.platform = Gem::Platform::RUBY
13
+
14
+ gem.author = "Benedict Eastaugh"
15
+ gem.email = "benedict@eastaugh.net"
16
+ gem.homepage = "https://github.com/othermedia/jsrebuild"
17
+
18
+ gem.summary = "Dynamic rebuilder for JavaScript projects"
19
+ gem.description = "Dynamically runs the Jake build tool to rebuild JavaScript
20
+ projects in development environments.".sub(/\s+/, " ")
21
+
22
+ gem.license = "BSD"
23
+
24
+ gem.add_dependency "cool.io", ">= 1.1.0"
25
+ gem.add_dependency "eventful", ">= 1.0.0"
26
+ gem.add_dependency "jake", ">= 1.0.1"
27
+ gem.add_dependency "oyster", ">= 0.9.5"
28
+
29
+ gem.executables = ['jsrebuild']
30
+ gem.require_path = 'lib'
31
+ gem.files = `git ls-files`.split(/\s+/)
32
+ end
@@ -0,0 +1,17 @@
1
+ require 'time'
2
+
3
+ require 'coolio'
4
+ require 'eventful'
5
+ require 'jake'
6
+
7
+ module JSRebuild
8
+ CONFIG_FILE = Jake::CONFIG_FILE
9
+ HELPER_FILE = Jake::HELPER_FILE
10
+
11
+ LOG_FORMAT = "%-020s %-10s %-040s %-07s"
12
+
13
+ require 'jsrebuild/version'
14
+ require 'jsrebuild/config'
15
+ require 'jsrebuild/watcher'
16
+ require 'jsrebuild/runner'
17
+ end
@@ -0,0 +1,18 @@
1
+ module JSRebuild
2
+
3
+ class Config < Jake::Build
4
+ def source_files
5
+ @packages.inject([]) { |files, (_, pkg)|
6
+ files.concat(pkg.files)
7
+ }
8
+ end
9
+
10
+ def config_file
11
+ Jake.path(@dir, Jake::CONFIG_FILE)
12
+ end
13
+
14
+ def helper_file
15
+ Jake.path(@dir, Jake::HELPER_FILE)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,64 @@
1
+ module JSRebuild
2
+ class Runner
3
+ def initialize(dir, interval, jake_options)
4
+ @dir = Jake.path(dir || Dir.getwd)
5
+ @jake_options = jake_options
6
+ @config = load_config!
7
+ @watcher = Watcher.new(interval, @config)
8
+ end
9
+
10
+ def rebuild!
11
+ Jake::Build.delete_observers
12
+
13
+ build = Jake::Build.new(@dir, @jake_options)
14
+
15
+ build.on(:file_created) do |build, pkg, build_type, path|
16
+ size = (File.size(path) / 1024.0).ceil
17
+ $stderr.puts LOG_FORMAT % [pkg.name, build_type, path.gsub(@dir, ''), "#{ size } kB"]
18
+ end
19
+
20
+ build.on(:file_not_changed) do |build, pkg, build_type, path|
21
+ $stderr.puts LOG_FORMAT % [pkg.name, build_type, path.gsub(@dir, ''), 'UP-TO-DATE']
22
+ end
23
+
24
+ begin
25
+ build.run!
26
+ rescue => err
27
+ $stderr.puts err.message + "\n" + (err.backtrace * "\n")
28
+ end
29
+ end
30
+
31
+ def load_config!
32
+ @config = Config.new(@dir, @jake_options)
33
+ end
34
+
35
+ def run!
36
+ %w{HUP INT}.each do |sig|
37
+ Signal.trap(sig) { exit! }
38
+ end
39
+
40
+ @watcher.on :config_change do |w, path|
41
+ load_config!
42
+ rebuild!
43
+ end
44
+
45
+ @watcher.on :helper_change do |w, path|
46
+ load_config!
47
+ rebuild!
48
+ end
49
+
50
+ @watcher.on :source_change do |w, path|
51
+ rebuild!
52
+ end
53
+
54
+ rebuild!
55
+
56
+ @watcher.start
57
+ end
58
+
59
+ def exit!
60
+ @watcher.stop
61
+ exit(true)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module JSRebuild
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,112 @@
1
+ module JSRebuild
2
+ # Every jsrebuild process has a Watcher, which keeps tabs on the config,
3
+ # helper and source files and notifies the application if any of them change.
4
+ class Watcher
5
+ include Eventful
6
+
7
+ # Set the interval at which files should be checked for changes, and pass
8
+ # in a JSRebuild::Config object which tells the watch which config, helper
9
+ # and source files it should watch.
10
+ def initialize(interval = 0.5, config)
11
+ @interval = interval
12
+ @config = config
13
+ @loop = nil
14
+ @watchers = nil
15
+ @config_watcher = nil
16
+ @helper_watcher = nil
17
+ end
18
+
19
+ # Start the watcher process.
20
+ def start
21
+ return unless @loop.nil?
22
+
23
+ config_file = @config.config_file
24
+ helper_file = @config.helper_file
25
+
26
+ @loop = Coolio::Loop.default
27
+
28
+ @config_watcher = FileWatcher.new(config_file, @interval)
29
+ @helper_watcher = FileWatcher.new(helper_file, @interval)
30
+
31
+ @config_watcher.on :change do
32
+ fire(:config_change, config_file)
33
+ reattach_source_watchers
34
+ end
35
+
36
+ @helper_watcher.on :change do
37
+ fire(:helper_change, helper_file)
38
+ reattach_source_watchers
39
+ end
40
+
41
+ @config_watcher.attach(@loop)
42
+ @helper_watcher.attach(@loop)
43
+
44
+ attach_source_watchers
45
+
46
+ @loop.run
47
+ end
48
+
49
+ # Detach all current source watchers and attach new ones.
50
+ #
51
+ # This is a simple and robust way of ensuring that when changes are made
52
+ # which change which files should be watched, only those files which should
53
+ # be watched are watched, and no others.
54
+ def reattach_source_watchers
55
+ detach_source_watchers
56
+ attach_source_watchers
57
+ end
58
+
59
+ # Attach a file watcher to each source file.
60
+ def attach_source_watchers
61
+ @source_watchers = {}
62
+
63
+ @config.source_files.each do |file|
64
+ watcher = FileWatcher.new(file, @interval)
65
+ @source_watchers[file] = watcher
66
+
67
+ watcher.on :change do
68
+ fire(:source_change, file)
69
+ end
70
+
71
+ watcher.attach(@loop)
72
+ end
73
+ end
74
+
75
+ # Detach all current source watchers.
76
+ def detach_source_watchers
77
+ unless @source_watchers.nil? || @source_watchers.empty?
78
+ @source_watchers.each do |file, watcher|
79
+ watcher.detach
80
+ end
81
+ end
82
+ end
83
+
84
+ # Detach all watchers and stop the event loop.
85
+ def stop
86
+ detach_source_watchers
87
+
88
+ @config_watcher.detach
89
+ @helper_watcher.detach
90
+
91
+ @loop.stop
92
+ end
93
+ end
94
+
95
+ # The FileWatcher class is a small extension to the Coolio::StatWatcher class
96
+ # which encapsulates one further piece of information, the last time the
97
+ # watched file was changed.
98
+ #
99
+ # When the watched file changes, FileWatcher objects notify any observers
100
+ # only when the file has been modified since it was last checked.
101
+ class FileWatcher < Coolio::StatWatcher
102
+ include Eventful
103
+
104
+ # Notify any observers if either the file no longer exists, or if the file
105
+ # has been modified since it was last checked.
106
+ def on_change(prev, current)
107
+ fire(:change) and return unless File.exists?(path)
108
+
109
+ fire(:change) if current.ctime > prev.ctime
110
+ end
111
+ end
112
+ end
@@ -0,0 +1 @@
1
+ $stderr.puts "Jake helper file running..."
@@ -0,0 +1,18 @@
1
+ ---
2
+ source_directory: source
3
+ build_directory: build
4
+ layout: together
5
+
6
+ builds:
7
+ source:
8
+ suffix: false
9
+ packer: false
10
+ min:
11
+ shrink_vars: true
12
+ private: true
13
+
14
+ packages:
15
+ fake:
16
+ files:
17
+ - fake_core
18
+ - fake_ui
@@ -0,0 +1 @@
1
+ var Fake = {};
@@ -0,0 +1,3 @@
1
+ var Faker = function(bar) {
2
+ this._foo = bar;
3
+ };
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsrebuild
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Benedict Eastaugh
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-12 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cool.io
16
+ requirement: &2152045800 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.1.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2152045800
25
+ - !ruby/object:Gem::Dependency
26
+ name: eventful
27
+ requirement: &2152045300 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2152045300
36
+ - !ruby/object:Gem::Dependency
37
+ name: jake
38
+ requirement: &2152044840 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.1
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *2152044840
47
+ - !ruby/object:Gem::Dependency
48
+ name: oyster
49
+ requirement: &2152044380 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.9.5
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *2152044380
58
+ description: ! "Dynamically runs the Jake build tool to rebuild JavaScript\n projects
59
+ in development environments."
60
+ email: benedict@eastaugh.net
61
+ executables:
62
+ - jsrebuild
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .gitignore
67
+ - Gemfile
68
+ - History.txt
69
+ - LICENSE
70
+ - README.md
71
+ - bin/jsrebuild
72
+ - jsrebuild.gemspec
73
+ - lib/jsrebuild.rb
74
+ - lib/jsrebuild/config.rb
75
+ - lib/jsrebuild/runner.rb
76
+ - lib/jsrebuild/version.rb
77
+ - lib/jsrebuild/watcher.rb
78
+ - test/Jakefile
79
+ - test/jake.yml
80
+ - test/source/fake_core.js
81
+ - test/source/fake_ui.js
82
+ homepage: https://github.com/othermedia/jsrebuild
83
+ licenses:
84
+ - BSD
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 1.8.7
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Dynamic rebuilder for JavaScript projects
107
+ test_files: []