jsrebuild 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []