cup 0.0.1 → 0.0.3
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.
- 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
|