cup 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,12 @@
1
+ module Cup
2
+ module NoopShell
3
+
4
+ module_function
5
+
6
+ def say *params
7
+ end
8
+
9
+ def say_status *params
10
+ end
11
+ end
12
+ 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
+
@@ -0,0 +1,3 @@
1
+ module Cup
2
+ VERSION = '0.0.3'
3
+ end
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
- def create name, options={}
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