weld 0.0.1.dev.20100402

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2010 Ryan Grove <ryan@wonko.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the 'Software'), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,8 @@
1
+ = Weld
2
+
3
+ Weld combines and minifies CSS and JavaScript files at runtime and build time.
4
+
5
+ == Status
6
+
7
+ It's working, but not quite finished yet. Stay tuned (or feel free to play
8
+ around if you're brave).
data/bin/weld ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'trollop'
5
+ require 'weld'
6
+
7
+ options = Trollop.options do
8
+ version "#{Weld::APP_NAME} #{Weld::APP_VERSION}\n" << Weld::APP_COPYRIGHT
9
+ banner <<-EOS
10
+ Weld combines and minifies CSS and JavaScript files at runtime and build time.
11
+
12
+ Usage:
13
+ weld [options] <component> [<component> ...]
14
+
15
+ Options:
16
+ EOS
17
+
18
+ opt :config, "Use the specified config file.", :short => '-c', :default => './weld.yaml'
19
+ opt :no_minify, "Don't perform any minification.", :short => :none
20
+ opt :output_dir, "Write welded files to the specified directory.", :short => '-o', :default => './'
21
+ opt :type, "Only weld components of the specified type ('css' or 'js').", :short => '-t', :type => :string
22
+ end
23
+
24
+ if options[:type_given] && !['css', 'js'].include?(options[:type])
25
+ abort "Error: Unsupported component type: #{options[:type]}\n" <<
26
+ "Try --help for help."
27
+ end
28
+
29
+ weld = Weld.new(options[:config])
30
+
31
+ components = ARGV.length > 0 ? ARGV : @weld.config['components'] || []
32
+ type = options[:type].to_sym if options[:type_given]
33
+
34
+ components.each do |name|
35
+ puts "Welding #{name}"
36
+
37
+ component = weld.component(name)
38
+ suffix = Time.now.strftime('-%Y%m%d%H%M')
39
+
40
+ if type
41
+ next if component.method(type).call.empty?
42
+
43
+ filename = "#{File.join(options[:output_dir], name)}#{suffix}.#{type}"
44
+
45
+ File.open(filename, 'w') do |file|
46
+ puts "--> #{filename}"
47
+ file.write(options[:no_minify] ? component.merge(type) : component.compress(type))
48
+ end
49
+ else
50
+ [:css, :js].each do |type|
51
+ next if component.method(type).call.empty?
52
+
53
+ filename = "#{File.join(options[:output_dir], name)}#{suffix}.#{type}"
54
+
55
+ File.open(filename, 'w') do |file|
56
+ puts "--> #{filename}"
57
+ file.write(options[:no_minify] ? component.merge(type) : component.compress(type))
58
+ end
59
+ end
60
+ end
61
+
62
+ puts
63
+ end
@@ -0,0 +1,40 @@
1
+ #
2
+ # This is a simple (but complete) example of a Weld config file.
3
+ #
4
+ ---
5
+ compressors:
6
+ css:
7
+ name: yui
8
+ options:
9
+ jar: /usr/local/bin/yuicompressor.jar
10
+
11
+ js:
12
+ name: yui
13
+ options:
14
+ jar: /usr/local/bin/yuicompressor.jar
15
+
16
+ sourcePaths:
17
+ - ../public/js
18
+ - ../public/css
19
+
20
+ components:
21
+ yui-3.1.0:
22
+ js:
23
+ - 'http://yui.yahooapis.com/3.1.0/build/yui/yui.js'
24
+ - 'http://yui.yahooapis.com/3.1.0/build/oop/oop-min.js'
25
+ - 'http://yui.yahooapis.com/3.1.0/build/event-custom/event-custom-min.js'
26
+ - 'http://yui.yahooapis.com/3.1.0/build/event/event-min.js'
27
+ - 'http://yui.yahooapis.com/3.1.0/build/dom/dom-min.js'
28
+ - 'http://yui.yahooapis.com/3.1.0/build/node/node-min.js'
29
+
30
+ my-awesome-website:
31
+ requires:
32
+ - yui-3.1.0
33
+
34
+ css:
35
+ - my-awesome-website.css
36
+ - so-awesome-it-hurts.css
37
+
38
+ js:
39
+ - my-awesome-website.js
40
+ - some-more-awesome-stuff.js
@@ -0,0 +1,18 @@
1
+ class Weld::Compressor::Yui < Weld::Compressor
2
+ def initialize(type, options = {})
3
+ super(type, options)
4
+
5
+ raise Weld::CompressorError, "YUI Compressor jar file not specified" unless @options['jar']
6
+ raise Weld::CompressorError, "YUI Compressor jar file not found: #{@options['jar']}" unless File.exist?(@options['jar'])
7
+ end
8
+
9
+ def compress(input)
10
+ Open3.popen3("java -jar '#{@options['jar']}' --type #{type}") do |stdin, stdout, stderr|
11
+ stdin.write(input)
12
+ stdin.close
13
+
14
+ stdout.read
15
+ # TODO: read stderr
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ require 'open3'
2
+
3
+ class Weld; class Compressor
4
+ autoload :Yui, 'weld/compressor/yui'
5
+
6
+ attr_reader :options, :type
7
+
8
+ def initialize(type, options = {})
9
+ @type = type
10
+ @options = options
11
+ end
12
+
13
+ def compress(input)
14
+ end
15
+
16
+ end; end
@@ -0,0 +1,37 @@
1
+ require 'sinatra/base'
2
+
3
+ class Weld::Server < Sinatra::Base
4
+
5
+ get %r{^/([^/\.]+)\.(css|js)$} do |name, type|
6
+ begin
7
+ @weld ||= Weld.new(settings.config_file)
8
+ rescue => ex
9
+ halt 500, ex.to_s
10
+ end
11
+
12
+ type = type.to_sym
13
+ no_minify = params.has_key?('no-minify') || params.has_key?('nominify')
14
+
15
+ content_type(type == :css ? 'text/css' : 'application/javascript',
16
+ :charset => 'utf-8')
17
+
18
+ begin
19
+ if no_minify
20
+ @weld.component(name).merge(type)
21
+ else
22
+ @weld.component(name).compress(type)
23
+ end
24
+
25
+ rescue Weld::ComponentNotFoundError,
26
+ Weld::FileNotFoundError => ex
27
+ halt 404, ex.to_s
28
+
29
+ rescue Weld::UnsupportedFileTypeError => ex
30
+ halt 400, ex.to_s
31
+
32
+ rescue => ex
33
+ halt 500, ex.to_s
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,9 @@
1
+ class Weld
2
+ APP_NAME = 'Weld'
3
+ APP_VERSION = '0.0.1.dev.20100402'
4
+ APP_AUTHOR = 'Ryan Grove'
5
+ APP_EMAIL = 'ryan@wonko.com'
6
+ APP_URL = 'http://wonko.com/'
7
+ APP_COPYRIGHT = 'Copyright (c) 2010 Ryan Grove <ryan@wonko.com>. All ' <<
8
+ 'rights reserved.'
9
+ end
data/lib/weld.rb ADDED
@@ -0,0 +1,118 @@
1
+ require 'open-uri'
2
+ require 'pathname'
3
+
4
+ require 'weld/compressor'
5
+ require 'weld/version'
6
+
7
+ class Weld
8
+ autoload :Server, 'weld/server'
9
+
10
+ attr_reader :config, :config_file
11
+
12
+ def initialize(config_file)
13
+ # TODO: handle exceptions
14
+ @config = YAML::load_file(config_file)
15
+ @config_file = config_file
16
+ end
17
+
18
+ def component(name)
19
+ unless definition = @config['components'][name]
20
+ raise ComponentNotFoundError, "Component not found: #{name}"
21
+ end
22
+
23
+ css = []
24
+ js = []
25
+ requires = definition['requires'] || []
26
+
27
+ # Resolve required components.
28
+ # TODO: handle circular dependencies?
29
+ requires.each do |name|
30
+ component = component(name)
31
+
32
+ css += component.css
33
+ js += component.js
34
+ end
35
+
36
+ css += definition['css'] || []
37
+ js += definition['js'] || []
38
+
39
+ Component.new(self, name, :css => css, :js => js, :requires => requires)
40
+ end
41
+
42
+ class Component
43
+ attr_reader :name, :requires
44
+ attr_accessor :css, :js
45
+
46
+ def initialize(weld, name, config = {})
47
+ raise ArgumentError, "weld must be a Weld instance" unless weld.is_a?(Weld)
48
+
49
+ @weld = weld
50
+ @name = name
51
+ @css = config[:css] || []
52
+ @js = config[:js] || []
53
+ @requires = config[:requires] || []
54
+
55
+ @file_cache = {}
56
+ end
57
+
58
+ def compress(type)
59
+ compressors = @weld.config['compressors']
60
+
61
+ unless compressors && compressors[type.to_s] &&
62
+ compressor_name = compressors[type.to_s]['name'].capitalize.to_sym
63
+ raise CompressorError, "No compressor configured"
64
+ end
65
+
66
+ options = compressors[type.to_s]['options'] || {}
67
+ compressor = Compressor.const_get(compressor_name).new(type, options)
68
+
69
+ compressor.compress(merge(type))
70
+ end
71
+
72
+ def merge(type)
73
+ raise UnsupportedFileTypeError, "Unsupported file type: #{type}" unless [:css, :js].include?(type.to_sym)
74
+
75
+ content = ''
76
+ method(type.to_sym).call.each {|f| content << read_file(f) + "\n" }
77
+ content
78
+ end
79
+
80
+ private
81
+
82
+ def read_file(filename)
83
+ filename = resolve_file(filename)
84
+
85
+ if filename.is_a?(URI)
86
+ open(filename, 'User-Agent' => "#{APP_NAME}/#{APP_VERSION}").read
87
+ else
88
+ File.read(filename)
89
+ end
90
+ end
91
+
92
+ def resolve_file(filename)
93
+ return @file_cache[filename] if @file_cache.has_key?(filename)
94
+
95
+ if filename =~ /^(?:https?|ftp):\/\//
96
+ @file_cache[filename] = URI.parse(filename)
97
+ else
98
+ (@weld.config['sourcePaths'] || []).each do |source_path|
99
+ full_path = if Pathname.new(source_path).relative?
100
+ File.join(File.dirname(@weld.config_file), source_path, filename)
101
+ else
102
+ File.join(source_path, filename)
103
+ end
104
+
105
+ return @file_cache[filename] = File.expand_path(full_path) if File.exist?(full_path)
106
+ end
107
+
108
+ raise FileNotFoundError, "File not found: #{filename}"
109
+ end
110
+ end
111
+ end
112
+
113
+ class Error < StandardError; end
114
+ class ComponentNotFoundError < Error; end
115
+ class CompressorError < Error; end
116
+ class FileNotFoundError < Error; end
117
+ class UnsupportedFileTypeError < Error; end
118
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: weld
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.dev.20100402
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Grove
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-04-02 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sinatra
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: "1.0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: trollop
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: "1.13"
34
+ version:
35
+ description:
36
+ email: ryan@wonko.com
37
+ executables:
38
+ - weld
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - LICENSE
45
+ - README.rdoc
46
+ - bin/weld
47
+ - examples/simple-config.yaml
48
+ - lib/weld/compressor/yui.rb
49
+ - lib/weld/compressor.rb
50
+ - lib/weld/server.rb
51
+ - lib/weld/version.rb
52
+ - lib/weld.rb
53
+ has_rdoc: true
54
+ homepage: http://wonko.com/
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options: []
59
+
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 1.8.6
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">"
71
+ - !ruby/object:Gem::Version
72
+ version: 1.3.1
73
+ version:
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.3.5
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Combines and minifies CSS and JavaScript files at runtime and build time.
81
+ test_files: []
82
+