middleman 3.0.0.alpha.4 → 3.0.0.alpha.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +1 -0
  2. data/.yardopts +7 -3
  3. data/CHANGELOG.md +4 -1
  4. data/bin/middleman +10 -24
  5. data/features/3rd_party_cli.feature +5 -0
  6. data/features/builder.feature +43 -25
  7. data/features/chained_templates.feature +8 -4
  8. data/features/clean_build.feature +24 -13
  9. data/features/cli.feature +121 -0
  10. data/features/coffee-script.feature +1 -1
  11. data/features/custom_layout_engines.feature +5 -2
  12. data/features/directory_index.feature +17 -10
  13. data/features/dynamic_pages.feature +11 -8
  14. data/features/fonts.feature +5 -2
  15. data/features/sprockets.feature +4 -2
  16. data/fixtures/3rd-party-command/config.rb +10 -0
  17. data/lib/middleman.rb +19 -12
  18. data/lib/middleman/base.rb +19 -5
  19. data/lib/middleman/cli.rb +36 -112
  20. data/lib/middleman/{builder.rb → cli/build.rb} +60 -51
  21. data/lib/middleman/cli/init.rb +47 -0
  22. data/lib/middleman/cli/server.rb +41 -0
  23. data/lib/middleman/core_extensions/assets.rb +1 -0
  24. data/lib/middleman/core_extensions/builder.rb +18 -0
  25. data/lib/middleman/core_extensions/compass.rb +6 -1
  26. data/lib/middleman/core_extensions/data.rb +66 -2
  27. data/lib/middleman/core_extensions/sprockets.rb +0 -1
  28. data/lib/middleman/guard.rb +41 -29
  29. data/lib/middleman/step_definitions.rb +7 -1
  30. data/lib/middleman/step_definitions/builder_steps.rb +22 -30
  31. data/lib/middleman/step_definitions/middleman_steps.rb +2 -0
  32. data/lib/middleman/templates.rb +12 -4
  33. data/lib/middleman/templates/default.rb +3 -1
  34. data/lib/middleman/templates/html5.rb +3 -1
  35. data/lib/middleman/templates/local.rb +5 -3
  36. data/lib/middleman/templates/mobile.rb +3 -1
  37. data/lib/middleman/version.rb +5 -1
  38. data/middleman-x86-mingw32.gemspec +11 -10
  39. data/middleman.gemspec +7 -11
  40. metadata +49 -44
@@ -1,8 +1,11 @@
1
1
  Feature: Web Fonts
2
2
 
3
3
  Scenario: Checking built folder for content
4
- Given a built app at "fonts-app"
5
- Then "stylesheets/fonts.css" should exist at "fonts-app" and include "/fonts/StMarie-Thin.otf"
4
+ Given a successfully built app at "fonts-app"
5
+ When I cd to "build"
6
+ Then the following files should exist:
7
+ | stylesheets/fonts.css |
8
+ And the file "stylesheets/fonts.css" should contain "/fonts/StMarie-Thin.otf"
6
9
 
7
10
  Scenario: Rendering scss
8
11
  Given the Server is running at "fonts-app"
@@ -21,8 +21,10 @@ Feature: Sprockets
21
21
  Then I should see "Hello One"
22
22
 
23
23
  Scenario: Multiple engine files should build correctly
24
- Given a built app at "test-app"
25
- Then "javascripts/multiple_engines.js" should exist at "test-app" and include "Hello One"
24
+ Given a successfully built app at "test-app"
25
+ When I cd to "build"
26
+ Then a file named "javascripts/multiple_engines.js" should exist
27
+ And the file "javascripts/multiple_engines.js" should contain "Hello One"
26
28
 
27
29
  Scenario: Sprockets CSS require //require
28
30
  Given the Server is running at "test-app"
@@ -0,0 +1,10 @@
1
+ class HelloWorld < Thor
2
+ default_task :say_hi
3
+
4
+ desc "hello", "Say hello"
5
+ def say_hi
6
+ puts "Hello World"
7
+ end
8
+ end
9
+
10
+ Middleman::Cli::Base.register(HelloWorld, :hello, "hello", "Say hello")
data/lib/middleman.rb CHANGED
@@ -1,17 +1,27 @@
1
+ require "rbconfig"
2
+
1
3
  # Setup our load paths
2
4
  libdir = File.dirname(__FILE__)
3
5
  $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
4
6
 
5
7
  # Top-level Middleman object
6
8
  module Middleman
9
+ WINDOWS = !!(RUBY_PLATFORM =~ /(mingw|bccwin|wince|mswin32)/i)
10
+ JRUBY = !!(RbConfig::CONFIG["RUBY_INSTALL_NAME"] =~ /^jruby/i)
11
+
7
12
  # Auto-load modules on-demand
8
13
  autoload :Base, "middleman/base"
9
14
  autoload :Cache, "middleman/cache"
10
- autoload :Builder, "middleman/builder"
11
- autoload :CLI, "middleman/cli"
12
15
  autoload :Templates, "middleman/templates"
13
16
  autoload :Guard, "middleman/guard"
14
17
 
18
+ module Cli
19
+ autoload :Base, "middleman/cli"
20
+ autoload :Build, "middleman/cli/build"
21
+ autoload :Init, "middleman/cli/init"
22
+ autoload :Server, "middleman/cli/server"
23
+ end
24
+
15
25
  # Custom Renderers
16
26
  module Renderers
17
27
  autoload :Haml, "middleman/renderers/haml"
@@ -156,12 +166,6 @@ module Middleman
156
166
 
157
167
  class << self
158
168
 
159
- # Where to look for custom templates
160
- # @returns [String]
161
- def templates_path
162
- File.join(File.expand_path("~/"), ".middleman")
163
- end
164
-
165
169
  # Automatically load extensions from available RubyGems
166
170
  # which contain the EXTENSION_FILE
167
171
  #
@@ -225,10 +229,13 @@ module Middleman
225
229
 
226
230
  app_class = options[:app] ||= ::Middleman.server.inst
227
231
  opts[:app] = app_class
228
- opts[:server] = 'thin'
229
-
230
- # require "thin"
231
- # ::Thin::Logging.silent = true if options[:debug] != "true"
232
+ opts[:server] = if ::Middleman::JRUBY
233
+ 'webrick' # Maybe Kirk?
234
+ else
235
+ require "thin"
236
+ ::Thin::Logging.silent = !options[:is_logging]
237
+ 'thin'
238
+ end
232
239
 
233
240
  server = ::Rack::Server.new(opts)
234
241
  server.start
@@ -91,6 +91,7 @@ class Middleman::Base
91
91
  # Use Rack middleware
92
92
  #
93
93
  # @param [Class] Middleware
94
+ # @return [void]
94
95
  def use(middleware, *args, &block)
95
96
  @middleware ||= []
96
97
  @middleware << [middleware, args, block]
@@ -99,6 +100,7 @@ class Middleman::Base
99
100
  # Add Rack App mapped to specific path
100
101
  #
101
102
  # @param [String] Path to map
103
+ # @return [void]
102
104
  def map(map, &block)
103
105
  @mappings ||= []
104
106
  @mappings << [map, block]
@@ -106,6 +108,7 @@ class Middleman::Base
106
108
 
107
109
  # Mix-in helper methods. Accepts either a list of Modules
108
110
  # and/or a block to be evaluated
111
+ # @return [void]
109
112
  def helpers(*extensions, &block)
110
113
  class_eval(&block) if block_given?
111
114
  include(*extensions) if extensions.any?
@@ -123,6 +126,7 @@ class Middleman::Base
123
126
  #
124
127
  # @param [Symbol] Unique key name
125
128
  # @param Default value
129
+ # @return [void]
126
130
  def set(key, value)
127
131
  @defaults ||= {}
128
132
  @defaults[key] = value
@@ -133,6 +137,7 @@ class Middleman::Base
133
137
  #
134
138
  # @param [Symbol] Name of the attribue
135
139
  # @param Attribute value
140
+ # @return [void]
136
141
  def set(key, value=nil, &block)
137
142
  setter = "#{key}=".to_sym
138
143
  self.class.send(:attr_accessor, key) if !respond_to?(setter)
@@ -263,6 +268,10 @@ class Middleman::Base
263
268
  @_current_path
264
269
  end
265
270
 
271
+ # Set the current path
272
+ #
273
+ # @param [String] path The new current path
274
+ # @return [void]
266
275
  def current_path=(path)
267
276
  @_current_path = path
268
277
  @request = Thor::CoreExt::HashWithIndifferentAccess.new({ :path => path })
@@ -423,7 +432,7 @@ class Middleman::Base
423
432
  # Expand a path to include the index file if it's a directory
424
433
  #
425
434
  # @private
426
- # @param [String] Request path
435
+ # @param [String] path Request path
427
436
  # @return [String] Path with index file if necessary
428
437
  def full_path(path)
429
438
  cache.fetch(:full_path, path) do
@@ -437,8 +446,9 @@ class Middleman::Base
437
446
 
438
447
  # Add a new mime-type for a specific extension
439
448
  #
440
- # @param [Symbol] File extension
441
- # @param [String] Mime type
449
+ # @param [Symbol] type File extension
450
+ # @param [String] value Mime type
451
+ # @return [void]
442
452
  def mime_type(type, value=nil)
443
453
  return type if type.nil? || type.to_s.include?('/')
444
454
  type = ".#{type}" unless type.to_s[0] == ?.
@@ -461,18 +471,20 @@ protected
461
471
  end
462
472
 
463
473
  # Set middleware at the class level
474
+ # @return [void]
464
475
  def use(middleware, *args, &block)
465
476
  self.class.use(middleware, *args, &block)
466
477
  end
467
478
 
468
479
  # Set mapped rack app at the class level
480
+ # @return [void]
469
481
  def map(map, &block)
470
482
  self.class.map(map, &block)
471
483
  end
472
484
 
473
485
  # Immediately send static file
474
486
  #
475
- # @param [String] File to send
487
+ # @param [String] path File to send
476
488
  def send_file(path)
477
489
  extension = File.extname(path)
478
490
  matched_mime = mime_type(extension)
@@ -488,7 +500,9 @@ protected
488
500
 
489
501
  # Set the content type for the current request
490
502
  #
491
- # @param [String] Content type
503
+ # @param [String] type Content type
504
+ # @param [Hash] params
505
+ # @return [void]
492
506
  def content_type(type = nil, params={})
493
507
  return res['Content-Type'] unless type
494
508
  default = params.delete :default
data/lib/middleman/cli.rb CHANGED
@@ -1,123 +1,47 @@
1
1
  require 'thor'
2
+ require "thor/group"
2
3
 
3
- module Middleman
4
- class CLI < Thor
5
- include Thor::Actions
6
- check_unknown_options!
7
- default_task :server
8
-
9
- class_option "help",
10
- :type => :boolean,
11
- :default => false,
12
- :aliases => "-h"
13
- def initialize(*)
14
- super
15
- help_check if options[:help]
16
- end
17
-
18
- desc "init NAME [options]", "Create new project NAME"
19
- available_templates = Middleman::Templates.registered.keys.join(", ")
20
- method_option "template",
21
- :aliases => "-T",
22
- :default => "default",
23
- :desc => "Use a project template: #{available_templates}"
24
- method_option "css_dir",
25
- :default => "stylesheets",
26
- :desc => 'The path to the css files'
27
- method_option "js_dir",
28
- :default => "javascripts",
29
- :desc => 'The path to the javascript files'
30
- method_option "images_dir",
31
- :default => "images",
32
- :desc => 'The path to the image files'
33
- method_option "rack",
34
- :type => :boolean,
35
- :default => false,
36
- :desc => 'Include a config.ru file'
37
- method_option "bundler",
38
- :type => :boolean,
39
- :default => false,
40
- :desc => 'Create a Gemfile and use Bundler to manage gems'
41
- def init(name)
42
- key = options[:template].to_sym
43
- unless Middleman::Templates.registered.has_key?(key)
44
- raise Thor::Error.new "Unknown project template '#{key}'"
45
- end
46
-
47
- thor_group = Middleman::Templates.registered[key]
48
- thor_group.new([name], options).invoke_all
49
- end
50
-
51
- desc "server [options]", "Start the preview server"
52
- method_option "environment",
53
- :aliases => "-e",
54
- :default => ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development',
55
- :desc => "The environment Middleman will run under"
56
- method_option :host,
57
- :type => :string,
58
- :aliases => "-h",
59
- # :required => true,
60
- :default => "0.0.0.0",
61
- :desc => "Bind to HOST address"
62
- method_option "port",
63
- :aliases => "-p",
64
- :default => "4567",
65
- :desc => "The port Middleman will listen on"
66
- method_option "debug",
67
- :type => :boolean,
68
- :default => false,
69
- :desc => 'Print debug messages'
70
- def server
71
- params = {
72
- :port => options["port"],
73
- :host => options["host"],
74
- :environment => options["environment"],
75
- :debug => options["debug"]
76
- }
77
-
78
- puts "== The Middleman is loading"
79
- Middleman::Guard.start(params)
80
- end
81
-
82
- desc "build", "Builds the static site for deployment"
83
- method_option :relative,
84
- :type => :boolean,
85
- :aliases => "-r",
86
- :default => false,
87
- :desc => 'Force relative urls'
88
- method_option :clean,
89
- :type => :boolean,
90
- :aliases => "-c",
91
- :default => false,
92
- :desc => 'Removes orpahand files or directories from build'
93
- method_option :glob,
94
- :type => :string,
95
- :aliases => "-g",
96
- :default => nil,
97
- :desc => 'Build a subset of the project'
98
- def build
99
- thor_group = Middleman::Builder.new([], options).invoke_all
100
- end
101
-
102
- desc "migrate", "Migrates an older project to the 2.0 structure"
103
- def migrate
104
- return if File.exists?("source")
105
- `mv public source`
106
- `cp -R views/* source/`
107
- `rm -rf views`
108
- end
109
-
4
+ # CLI Module
5
+ module Middleman::Cli
6
+
7
+ class Base < Thor
110
8
  desc "version", "Show version"
111
9
  def version
112
10
  require 'middleman/version'
113
11
  say "Middleman #{Middleman::VERSION}"
114
12
  end
115
13
 
116
- private
117
-
118
- def help_check
119
- help self.class.send(:retrieve_task_name, ARGV.dup)
120
- exit 0
14
+ def help(meth = nil, subcommand = false)
15
+ if meth && !self.respond_to?(meth)
16
+ klass, task = Thor::Util.find_class_and_task_by_namespace("#{meth}:#{meth}")
17
+ klass.start(["-h", task].compact, :shell => self.shell)
18
+ else
19
+ list = []
20
+ Thor::Util.thor_classes_in(Middleman::Cli).each do |klass|
21
+ list += klass.printable_tasks(false)
22
+ end
23
+ list.sort!{ |a,b| a[0] <=> b[0] }
24
+
25
+ shell.say "Tasks:"
26
+ shell.print_table(list, :ident => 2, :truncate => true)
27
+ shell.say
28
+ end
29
+ end
30
+
31
+ def method_missing(meth, *args)
32
+ meth = meth.to_s
33
+
34
+ if self.class.map.has_key?(meth)
35
+ meth = self.class.map[meth]
36
+ end
37
+
38
+ klass, task = Thor::Util.find_class_and_task_by_namespace("#{meth}:#{meth}")
39
+ args.unshift(task) if task
40
+ klass.start(args, :shell => self.shell)
121
41
  end
122
42
  end
123
43
  end
44
+
45
+ require "middleman/cli/init"
46
+ require "middleman/cli/server"
47
+ require "middleman/cli/build"
@@ -1,11 +1,44 @@
1
- require "thor"
2
- require "thor/group"
1
+ require "rack"
3
2
  require "rack/test"
4
- require "find"
5
3
 
6
- module Middleman
7
- class Builder < Thor::Group
4
+ module Middleman::Cli
5
+ class Build < Thor
8
6
  include Thor::Actions
7
+ check_unknown_options!
8
+
9
+ namespace :build
10
+
11
+ desc "build [options]", "Builds the static site for deployment"
12
+ method_option :relative,
13
+ :type => :boolean,
14
+ :aliases => "-r",
15
+ :default => false,
16
+ :desc => 'Force relative urls'
17
+ method_option :clean,
18
+ :type => :boolean,
19
+ :aliases => "-c",
20
+ :default => false,
21
+ :desc => 'Removes orpahand files or directories from build'
22
+ method_option :glob,
23
+ :type => :string,
24
+ :aliases => "-g",
25
+ :default => nil,
26
+ :desc => 'Build a subset of the project'
27
+ def build
28
+ if options.has_key?("relative") && options["relative"]
29
+ self.class.shared_instance.activate :relative_assets
30
+ end
31
+
32
+ self.class.shared_rack
33
+
34
+ opts = {}
35
+ opts[:glob] = options["glob"] if options.has_key?("glob")
36
+ opts[:clean] = options["clean"] if options.has_key?("clean")
37
+
38
+ action GlobAction.new(self, self.class.shared_instance, opts)
39
+
40
+ self.class.shared_instance.run_hook :after_build, self
41
+ end
9
42
 
10
43
  class << self
11
44
  def shared_instance
@@ -13,11 +46,11 @@ module Middleman
13
46
  set :environment, :build
14
47
  end
15
48
  end
16
-
49
+
17
50
  def shared_server
18
51
  @_shared_server ||= shared_instance.class
19
52
  end
20
-
53
+
21
54
  def shared_rack
22
55
  @_shared_rack ||= begin
23
56
  mock = ::Rack::MockSession.new(shared_server.to_rack_app)
@@ -28,6 +61,8 @@ module Middleman
28
61
  end
29
62
  end
30
63
 
64
+ source_root(shared_instance.root)
65
+
31
66
  # @private
32
67
  module ThorActions
33
68
  # Render a template to a file.
@@ -36,12 +71,12 @@ module Middleman
36
71
  config = args.last.is_a?(Hash) ? args.pop : {}
37
72
  destination = args.first || source
38
73
 
39
- request_path = destination.sub(/^#{::Middleman::Builder.shared_instance.build_dir}/, "")
74
+ request_path = destination.sub(/^#{self.class.shared_instance.build_dir}/, "")
40
75
 
41
76
  begin
42
- destination, request_path = ::Middleman::Builder.shared_instance.reroute_builder(destination, request_path)
77
+ destination, request_path = self.class.shared_instance.reroute_builder(destination, request_path)
43
78
 
44
- response = ::Middleman::Builder.shared_rack.get(request_path.gsub(/\s/, "%20"))
79
+ response = self.class.shared_rack.get(request_path.gsub(/\s/, "%20"))
45
80
 
46
81
  create_file(destination, response.body, config)
47
82
 
@@ -52,36 +87,8 @@ module Middleman
52
87
  end
53
88
  end
54
89
  end
90
+
55
91
  include ThorActions
56
-
57
- class_option :relative, :type => :boolean, :aliases => "-r", :default => false, :desc => 'Override the config.rb file and force relative urls'
58
- class_option :glob, :type => :string, :aliases => "-g", :default => nil, :desc => 'Build a subset of the project'
59
-
60
- def initialize(*args)
61
- super
62
-
63
- if options.has_key?("relative") && options["relative"]
64
- self.class.shared_instance.activate :relative_assets
65
- end
66
- end
67
-
68
- def source_paths
69
- @source_paths ||= [
70
- self.class.shared_instance.root
71
- ]
72
- end
73
-
74
- def build_all_files
75
- self.class.shared_rack
76
-
77
- opts = { }
78
- opts[:glob] = options["glob"] if options.has_key?("glob")
79
- opts[:clean] = options["clean"] if options.has_key?("clean")
80
-
81
- action GlobAction.new(self, self.class.shared_instance, opts)
82
-
83
- self.class.shared_instance.run_hook :after_build, self
84
- end
85
92
  end
86
93
 
87
94
  # @private
@@ -92,9 +99,9 @@ module Middleman
92
99
  @app = app
93
100
  source = @app.source
94
101
  @destination = @app.build_dir
95
-
102
+
96
103
  @source = File.expand_path(base.find_in_source_paths(source.to_s))
97
-
104
+
98
105
  super(base, destination, config)
99
106
  end
100
107
 
@@ -109,7 +116,7 @@ module Middleman
109
116
  end
110
117
 
111
118
  protected
112
-
119
+
113
120
  def clean!
114
121
  files = @cleaning_queue.select { |q| File.file? q }
115
122
  directories = @cleaning_queue.select { |q| File.directory? q }
@@ -124,7 +131,7 @@ module Middleman
124
131
  base.remove_file d, :force => true if directory_empty? d
125
132
  end
126
133
  end
127
-
134
+
128
135
  def cleaning?
129
136
  @config.has_key?(:clean) && @config[:clean]
130
137
  end
@@ -142,20 +149,20 @@ module Middleman
142
149
  end
143
150
  end if File.exist?(@destination)
144
151
  end
145
-
152
+
146
153
  def execute!
147
154
  sort_order = %w(.png .jpeg .jpg .gif .bmp .svg .svgz .ico .woff .otf .ttf .eot .js .css)
148
-
155
+
149
156
  paths = @app.sitemap.all_paths.sort do |a, b|
150
157
  a_ext = File.extname(a)
151
158
  b_ext = File.extname(b)
152
-
159
+
153
160
  a_idx = sort_order.index(a_ext) || 100
154
161
  b_idx = sort_order.index(b_ext) || 100
155
-
162
+
156
163
  a_idx <=> b_idx
157
164
  end
158
-
165
+
159
166
  paths.each do |path|
160
167
  file_source = path
161
168
  file_destination = File.join(given_destination, file_source.gsub(source, '.'))
@@ -168,15 +175,17 @@ module Middleman
168
175
  elsif @app.sitemap.ignored?(file_source)
169
176
  next
170
177
  end
171
-
178
+
172
179
  if @config[:glob]
173
180
  next unless File.fnmatch(@config[:glob], file_source)
174
181
  end
175
-
182
+
176
183
  file_destination = base.tilt_template(file_source, file_destination, { :force => true })
177
184
 
178
185
  @cleaning_queue.delete(file_destination) if cleaning?
179
186
  end
180
187
  end
181
188
  end
182
- end
189
+
190
+ Base.map({ "b" => "build" })
191
+ end