cup 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/.pryrc +9 -0
- data/.rdebugrc +0 -0
- data/.rspec +2 -0
- data/Gemfile.lock +115 -0
- data/README.md +82 -2
- data/Rakefile +1 -3
- data/TODO +13 -0
- data/bin/cup +2 -17
- data/cup.gemspec +27 -11
- data/js/extra_matchers.js +29 -0
- data/lib/cup/builder.rb +127 -0
- data/lib/cup/command_line.rb +225 -0
- data/lib/cup/cupfile.rb +116 -0
- data/lib/cup/directory.rb +96 -0
- data/lib/cup/noop_shell.rb +12 -0
- data/lib/cup/server/app.rb +138 -0
- data/lib/cup/server/middleware.rb +27 -0
- data/lib/cup/server/view_scope.rb +108 -0
- data/lib/cup/server/visual_specs.rb +33 -0
- data/lib/cup/version.rb +3 -0
- data/lib/cup.rb +54 -2
- data/spec/cup/builder_spec.rb +164 -0
- data/spec/cup/command_line_spec.rb +182 -0
- data/spec/cup/cupfile_spec.rb +228 -0
- data/spec/cup/directory_spec.rb +223 -0
- data/spec/cup/server/app_spec.rb +63 -0
- data/spec/cup/server/visual_specs_spec.rb +30 -0
- data/spec/env.rb +2 -0
- data/spec/spec_helper.rb +28 -1
- data/spec/support/javascript_load_order_acceptor.rb +63 -0
- data/spec/support/javascripts_matchers.rb +22 -0
- data/spec/support/macros.rb +74 -0
- data/spec/support/stub_helpers.rb +30 -0
- data/views/blank.slim +9 -0
- data/views/cup.coffee +4 -0
- data/views/cup.sass +167 -0
- data/views/layout.slim +53 -0
- data/views/not_found.slim +3 -0
- data/views/root.slim +42 -0
- data/views/spec.slim +5 -0
- data/views/visual.slim +13 -0
- metadata +197 -22
- data/.versionify +0 -1
- data/spec/cup_cli.spec.rb +0 -12
data/lib/cup/cupfile.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module Cup
|
4
|
+
class Cupfile
|
5
|
+
include ActiveModel::Validations
|
6
|
+
class CupfileError < RuntimeError; end
|
7
|
+
|
8
|
+
attr_accessor :path
|
9
|
+
attr_reader :path, :name, :version, :license, :before_build, :after_build, :uglifier_options
|
10
|
+
|
11
|
+
validates_presence_of :name, :version, :path
|
12
|
+
validate :license_file_exists?
|
13
|
+
|
14
|
+
def initialize path
|
15
|
+
|
16
|
+
@path = path
|
17
|
+
@javascripts = {}
|
18
|
+
@uglifier_options = {}
|
19
|
+
@before_build = lambda {}
|
20
|
+
@after_build = lambda {}
|
21
|
+
|
22
|
+
%w{vendor spec lib src}.each do |dir|
|
23
|
+
set_javascript_patterns_for dir.to_sym, :*
|
24
|
+
end
|
25
|
+
|
26
|
+
cup_define_block = eval(File.read(path), binding, path.to_s)
|
27
|
+
DSL.interpret self, &cup_define_block
|
28
|
+
end
|
29
|
+
|
30
|
+
def javascripts
|
31
|
+
@javascripts
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def set_javascript_patterns_for subdir, *patterns
|
37
|
+
|
38
|
+
current_directory = File.dirname(File.expand_path(self.path))
|
39
|
+
|
40
|
+
@javascripts[subdir] = patterns.map do |pattern|
|
41
|
+
|
42
|
+
default_catch_all = pattern == :*
|
43
|
+
|
44
|
+
pattern = '**/*.js' if default_catch_all
|
45
|
+
|
46
|
+
if pattern
|
47
|
+
expanded_pattern = current_directory + "/#{subdir}/#{pattern}"
|
48
|
+
FileList[expanded_pattern].select do |f|
|
49
|
+
if subdir == :spec and f.start_with?(current_directory + "/spec/visual")
|
50
|
+
false
|
51
|
+
else
|
52
|
+
File.extname(f).downcase == '.js'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end.flatten.compact.uniq
|
57
|
+
end
|
58
|
+
|
59
|
+
def license_file_exists?
|
60
|
+
unless license.nil? or path.nil?
|
61
|
+
license_path = "#{File.dirname(File.expand_path(path))}/#{license}"
|
62
|
+
errors.add :license, "#{license} is not a valid license file" unless File.exist?(license_path) and not File.directory?(license_path)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class DSL < BasicObject
|
67
|
+
private_class_method :new
|
68
|
+
|
69
|
+
## DSL members
|
70
|
+
## setters
|
71
|
+
%W{version name license uglifier_options}.each do |m|
|
72
|
+
define_method m do |value|
|
73
|
+
@cupfile.instance_variable_set "@#{m}", value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.interpret cupfile, &block
|
78
|
+
new(cupfile).instance_eval &block
|
79
|
+
cupfile
|
80
|
+
end
|
81
|
+
|
82
|
+
def initialize cupfile
|
83
|
+
@cupfile = cupfile
|
84
|
+
end
|
85
|
+
|
86
|
+
def javascripts &block
|
87
|
+
JavascriptsDSL.interpret @cupfile, &block
|
88
|
+
end
|
89
|
+
|
90
|
+
## block cachers
|
91
|
+
def before_build &block
|
92
|
+
@cupfile.instance_variable_set :@before_build, block
|
93
|
+
end
|
94
|
+
|
95
|
+
def after_build &block
|
96
|
+
@cupfile.instance_variable_set :@after_build, block
|
97
|
+
end
|
98
|
+
|
99
|
+
class JavascriptsDSL < BasicObject
|
100
|
+
|
101
|
+
def initialize cupfile
|
102
|
+
@cupfile = cupfile
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.interpret cupfile, &block
|
106
|
+
new(cupfile).instance_eval &block
|
107
|
+
cupfile
|
108
|
+
end
|
109
|
+
|
110
|
+
def method_missing name, *args, &block
|
111
|
+
@cupfile.send :set_javascript_patterns_for, name, *(args.flatten)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'rake'
|
3
|
+
require 'cup/cupfile'
|
4
|
+
|
5
|
+
module Cup
|
6
|
+
|
7
|
+
# Represents the directory that holds a cup
|
8
|
+
class Directory
|
9
|
+
|
10
|
+
attr_reader :path
|
11
|
+
|
12
|
+
def initialize path
|
13
|
+
@path = Pathname.new File.expand_path(path.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
# so that current can be overridden for all tests
|
17
|
+
def self.__current__
|
18
|
+
new('.')
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.current
|
22
|
+
__current__
|
23
|
+
end
|
24
|
+
|
25
|
+
def cupfile
|
26
|
+
@cupfile ||= Cup::Cupfile.new(path + 'Cupfile')
|
27
|
+
|
28
|
+
unless @cupfile.valid?
|
29
|
+
raise Cup::Cupfile::CupfileError.new("Cupfile not valid: #{@cupfile.path.to_s}\n#{@cupfile.errors.full_messages}")
|
30
|
+
end
|
31
|
+
|
32
|
+
@cupfile
|
33
|
+
end
|
34
|
+
|
35
|
+
def name
|
36
|
+
File.basename path.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
def concatenated(opts={})
|
40
|
+
output = "build/#{name}-#{cupfile.version}.js"
|
41
|
+
opts[:relative] ? output : "#{self.path}/#{output}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def minified(opts={})
|
45
|
+
output = "build/#{name}-#{cupfile.version}.min.js"
|
46
|
+
opts[:relative] ? output : "#{self.path}/#{output}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def license(opts={})
|
50
|
+
license = "#{cupfile.license}"
|
51
|
+
opts[:relative] ? license : "#{self.path}/#{license}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def javascripts scheme=nil
|
55
|
+
|
56
|
+
load_paths = case scheme
|
57
|
+
when :spec
|
58
|
+
['vendor', 'spec', 'lib', 'src']
|
59
|
+
when :build_input
|
60
|
+
['lib', 'src']
|
61
|
+
when :spec_concatenated, :spec_minified
|
62
|
+
['vendor', 'spec', 'build']
|
63
|
+
when :debug
|
64
|
+
['vendor', 'lib', 'src']
|
65
|
+
else
|
66
|
+
raise "scheme not known: #{scheme}"
|
67
|
+
end
|
68
|
+
|
69
|
+
javascripts = load_paths.map do |load_path|
|
70
|
+
if load_path == 'build'
|
71
|
+
build_for scheme
|
72
|
+
else
|
73
|
+
cupfile.javascripts[load_path.to_sym].map{|filepath| Pathname.new(filepath).to_s}
|
74
|
+
end
|
75
|
+
end.flatten
|
76
|
+
|
77
|
+
javascripts
|
78
|
+
end
|
79
|
+
|
80
|
+
def stylesheets
|
81
|
+
FileList['**/*.css'].map{|f| Pathname.new(f).expand_path}
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def build_for scheme
|
86
|
+
case scheme
|
87
|
+
when :spec_concatenated
|
88
|
+
concatenated
|
89
|
+
when :spec_minified
|
90
|
+
minified
|
91
|
+
else
|
92
|
+
raise "scheme :#{scheme} not expected to include 'build' load path"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'cup/directory'
|
2
|
+
require 'cup/server/view_scope'
|
3
|
+
require 'cup/server/middleware'
|
4
|
+
|
5
|
+
require 'sinatra/base'
|
6
|
+
require 'yard'
|
7
|
+
require 'json'
|
8
|
+
require 'slim'
|
9
|
+
require 'sass'
|
10
|
+
require 'coffee_script'
|
11
|
+
|
12
|
+
begin
|
13
|
+
require 'thin'
|
14
|
+
Thin::Logging.debug = :log
|
15
|
+
rescue LoadError
|
16
|
+
end
|
17
|
+
|
18
|
+
module Cup
|
19
|
+
module Server
|
20
|
+
class App < Sinatra::Base
|
21
|
+
|
22
|
+
use Middleware
|
23
|
+
|
24
|
+
configure(:development) do
|
25
|
+
require 'ruby-debug'
|
26
|
+
require 'sinatra/reloader'
|
27
|
+
register Sinatra::Reloader
|
28
|
+
also_reload "#{File.expand_path('../../..', __FILE__)}/**/*.rb"
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.gem_root_path *params
|
32
|
+
# uses a file relative version so that it points to the live files during development
|
33
|
+
File.expand_path(File.join('../../../..', *params), __FILE__)
|
34
|
+
end
|
35
|
+
|
36
|
+
set :server, %w{thin mongrel webrick}
|
37
|
+
set :views, gem_root_path('views')
|
38
|
+
set :public_folder, Cup::Directory.current.path.to_s
|
39
|
+
|
40
|
+
def view_scope(javascripts_scheme=:debug)
|
41
|
+
@view_scope = ViewScope.new self, javascripts_scheme
|
42
|
+
end
|
43
|
+
|
44
|
+
def view (template, options={})
|
45
|
+
|
46
|
+
options = {
|
47
|
+
:scope => view_scope(options.delete(:javascripts_scheme) || :debug),
|
48
|
+
:layout => true
|
49
|
+
}.merge options
|
50
|
+
|
51
|
+
slim template, options
|
52
|
+
end
|
53
|
+
|
54
|
+
def visuals
|
55
|
+
@visuals ||= VisualSpecs.get
|
56
|
+
end
|
57
|
+
|
58
|
+
def gem_root_path *params
|
59
|
+
self.class.gem_root_path *params
|
60
|
+
end
|
61
|
+
|
62
|
+
get '/cup.sass' do
|
63
|
+
sass File.read(gem_root_path('views/cup.sass'))
|
64
|
+
end
|
65
|
+
|
66
|
+
get '/cup.coffee' do
|
67
|
+
coffee File.read(gem_root_path('views/cup.coffee'))
|
68
|
+
end
|
69
|
+
|
70
|
+
get '/' do
|
71
|
+
view :root
|
72
|
+
end
|
73
|
+
|
74
|
+
get '/concatenate' do
|
75
|
+
|
76
|
+
content_type 'text/javascript'
|
77
|
+
|
78
|
+
result = Cup.build[:concatenated]
|
79
|
+
if result[:status] == :ok
|
80
|
+
body result[:output]
|
81
|
+
else
|
82
|
+
redirect '/'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
get '/minify' do
|
87
|
+
|
88
|
+
content_type 'text/javascript'
|
89
|
+
|
90
|
+
result = Cup.build[:minified]
|
91
|
+
if result[:status] == :ok
|
92
|
+
body result[:output]
|
93
|
+
else
|
94
|
+
redirect '/'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
get '/debug' do
|
99
|
+
view ''
|
100
|
+
end
|
101
|
+
|
102
|
+
get '/empty' do
|
103
|
+
redirect '/' if view_scope.build_status == :failed
|
104
|
+
view '', :layout => :blank
|
105
|
+
end
|
106
|
+
|
107
|
+
get '/spec' do
|
108
|
+
view :spec, :javascripts_scheme => :spec
|
109
|
+
end
|
110
|
+
|
111
|
+
get '/spec/concatenated' do
|
112
|
+
view :spec, :javascripts_scheme => :spec_concatenated
|
113
|
+
end
|
114
|
+
|
115
|
+
get '/spec/minified' do
|
116
|
+
view :spec, :javascripts_scheme => :spec_minified
|
117
|
+
end
|
118
|
+
|
119
|
+
get '/spec/visual' do
|
120
|
+
view :visual
|
121
|
+
end
|
122
|
+
|
123
|
+
get '/spec/visual/*' do |visual|
|
124
|
+
visual = visuals[visual]
|
125
|
+
|
126
|
+
pass if visual.nil? or not File.exist?(visual.full_path)
|
127
|
+
|
128
|
+
redirect '/spec/visual' if view_scope.build_status == :failed
|
129
|
+
|
130
|
+
view File.read(visual.full_path), :layout => :blank
|
131
|
+
end
|
132
|
+
|
133
|
+
not_found do
|
134
|
+
view :not_found
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rack/directory'
|
2
|
+
|
3
|
+
module Cup
|
4
|
+
module Server
|
5
|
+
class Middleware
|
6
|
+
|
7
|
+
def initialize app
|
8
|
+
@app = app
|
9
|
+
@directory = Rack::Directory.new(Cup::Directory.current.path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
|
14
|
+
status, headers, response = @app.call(env)
|
15
|
+
|
16
|
+
if status == 404
|
17
|
+
directory_status, *result = @directory.call(env)
|
18
|
+
if (200...300).include? directory_status
|
19
|
+
status, headers, response = directory_status, *result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
[status, headers, response]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'yard'
|
2
|
+
require 'cup'
|
3
|
+
require 'cup/directory'
|
4
|
+
require 'cup/server/visual_specs'
|
5
|
+
|
6
|
+
module Cup
|
7
|
+
module Server
|
8
|
+
class ViewScope
|
9
|
+
|
10
|
+
def initialize server, javascripts_scheme=nil
|
11
|
+
@server = server
|
12
|
+
@javascripts_scheme = javascripts_scheme
|
13
|
+
end
|
14
|
+
|
15
|
+
def name
|
16
|
+
Cup.cup_name
|
17
|
+
end
|
18
|
+
|
19
|
+
def build_status
|
20
|
+
build_result[:status]
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_result
|
24
|
+
#return {:status => :failed, :exception => 'you went wrong'}
|
25
|
+
@build_result ||= begin
|
26
|
+
result = Cup.build
|
27
|
+
result[:concatenated][:status] == :ok ? result[:minified] : result[:concatenated]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def version
|
32
|
+
Cup.version
|
33
|
+
end
|
34
|
+
|
35
|
+
def cup_version
|
36
|
+
Cup::VERSION
|
37
|
+
end
|
38
|
+
|
39
|
+
def stylesheets
|
40
|
+
@stylesheets ||= Cup::Directory.current.stylesheets.map do |src|
|
41
|
+
'/' + File.relative_path(Cup::Directory.current.path, src)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def javascripts
|
46
|
+
@javascripts ||= if @javascripts_scheme.nil?
|
47
|
+
[]
|
48
|
+
else
|
49
|
+
Cup::Directory.current.javascripts(@javascripts_scheme).map do |src|
|
50
|
+
'/' + File.relative_path(Cup::Directory.current.path, src)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def path
|
56
|
+
Cup::Directory.current.path
|
57
|
+
end
|
58
|
+
|
59
|
+
def concatenated
|
60
|
+
File.basename Cup.concatenated(:relative => true)
|
61
|
+
end
|
62
|
+
|
63
|
+
def concatenated_size
|
64
|
+
"#{File.exist?(Cup.concatenated) ? File.size(Cup.concatenated) : 0} bytes"
|
65
|
+
end
|
66
|
+
|
67
|
+
def minified
|
68
|
+
File.basename Cup.minified(:relative => true)
|
69
|
+
end
|
70
|
+
|
71
|
+
def minified_size
|
72
|
+
"#{File.exist?(Cup.minified) ? File.size(Cup.minified) : 0} bytes"
|
73
|
+
end
|
74
|
+
|
75
|
+
def minified_percent_available?
|
76
|
+
File.exists?(Cup.concatenated) and File.size(Cup.concatenated) > 0
|
77
|
+
end
|
78
|
+
|
79
|
+
def minified_percent
|
80
|
+
|
81
|
+
concatenated_size = File.size(Cup.concatenated).to_f
|
82
|
+
minified_size = File.size(Cup.minified).to_f
|
83
|
+
|
84
|
+
(100*(minified_size / concatenated_size)).round(2)
|
85
|
+
end
|
86
|
+
|
87
|
+
def lib_count
|
88
|
+
Cup::Directory.current.cupfile.javascripts[:lib].count
|
89
|
+
end
|
90
|
+
|
91
|
+
def src_count
|
92
|
+
Cup::Directory.current.cupfile.javascripts[:src].count
|
93
|
+
end
|
94
|
+
|
95
|
+
def file_list
|
96
|
+
Dir["#{Cup::Directory.current.path}/**/*"].select do |full_path|
|
97
|
+
File.file?(full_path)
|
98
|
+
end.map do |full_path|
|
99
|
+
File.relative_path(Cup::Directory.current.path, full_path)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def visuals
|
104
|
+
@server.visuals.values
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'yard'
|
2
|
+
require 'cup/directory'
|
3
|
+
|
4
|
+
module Cup
|
5
|
+
module Server
|
6
|
+
# not a member of Cup::Directory incase we ever want to search for visuals in arbitrary directories
|
7
|
+
module VisualSpecs
|
8
|
+
module_function
|
9
|
+
|
10
|
+
class VisualSpec
|
11
|
+
attr_accessor :href, :name, :full_path
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(directory = Cup::Directory.current.path + 'spec' + 'visual')
|
15
|
+
|
16
|
+
visuals = {}
|
17
|
+
|
18
|
+
Dir["#{File.expand_path(directory)}/**/*.slim"].select { |path| File.file?(path) }.each do |full_path|
|
19
|
+
|
20
|
+
href = '/' + File.relative_path(Cup::Directory.current.path, full_path).match(/(.*)\.slim$/)[1]
|
21
|
+
name = File.relative_path(File.expand_path(directory), full_path).match(/(.*)\.slim$/)[1]
|
22
|
+
|
23
|
+
visuals[name] = VisualSpec.new.tap do |v|
|
24
|
+
v.href, v.name, v.full_path = href, name, full_path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
visuals
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
data/lib/cup/version.rb
ADDED
data/lib/cup.rb
CHANGED
@@ -1,5 +1,57 @@
|
|
1
|
+
require 'cup/version'
|
2
|
+
require 'cup/directory'
|
3
|
+
require 'cup/cupfile'
|
4
|
+
require 'cup/builder'
|
5
|
+
|
1
6
|
module Cup
|
2
|
-
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def version *params
|
10
|
+
directory.cupfile.version *params
|
11
|
+
end
|
12
|
+
|
13
|
+
def cup_name *params
|
14
|
+
directory.cupfile.name *params
|
15
|
+
end
|
16
|
+
|
17
|
+
def concatenated *params
|
18
|
+
directory.concatenated *params
|
19
|
+
end
|
20
|
+
|
21
|
+
def minified *params
|
22
|
+
directory.minified *params
|
23
|
+
end
|
24
|
+
|
25
|
+
def build! *params
|
26
|
+
Cup::Builder.new(directory).build! *params
|
27
|
+
end
|
28
|
+
|
29
|
+
def build *params
|
30
|
+
Cup::Builder.new(directory).build *params
|
31
|
+
end
|
3
32
|
|
33
|
+
def concatenate! *params
|
34
|
+
Cup::Builder.new(directory).concatenate! *params
|
35
|
+
end
|
36
|
+
|
37
|
+
def concatenate *params
|
38
|
+
Cup::Builder.new(directory).concatenate *params
|
39
|
+
end
|
40
|
+
|
41
|
+
def minify! *params
|
42
|
+
Cup::Builder.new(directory).minify! *params
|
43
|
+
end
|
44
|
+
|
45
|
+
def minify *params
|
46
|
+
Cup::Builder.new(directory).minify *params
|
47
|
+
end
|
48
|
+
|
49
|
+
def define &block
|
50
|
+
block
|
51
|
+
end
|
52
|
+
private
|
53
|
+
def directory
|
54
|
+
@directory ||= Cup::Directory.current
|
55
|
+
end
|
4
56
|
end
|
5
|
-
end
|
57
|
+
end
|