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

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.
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