montage 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/History.md +23 -0
  2. data/Rakefile +2 -4
  3. data/VERSION +1 -1
  4. data/bin/montage +11 -4
  5. data/lib/montage/commands/generate.rb +72 -11
  6. data/lib/montage/commands/init.rb +5 -11
  7. data/lib/montage/commands.rb +51 -18
  8. data/lib/montage/project.rb +54 -39
  9. data/lib/montage/source.rb +15 -44
  10. data/lib/montage/sprite.rb +25 -37
  11. data/lib/montage/sprite_definition.rb +127 -0
  12. data/lib/montage/templates/montage.yml +29 -19
  13. data/lib/montage/templates/sass_mixins.erb +1 -1
  14. data/lib/montage/templates/sources/{book.png → one/book.png} +0 -0
  15. data/lib/montage/templates/sources/{box-label.png → one/box-label.png} +0 -0
  16. data/lib/montage/templates/sources/{calculator.png → one/calculator.png} +0 -0
  17. data/lib/montage/templates/sources/{calendar-month.png → one/calendar-month.png} +0 -0
  18. data/lib/montage/templates/sources/{camera.png → one/camera.png} +0 -0
  19. data/lib/montage/templates/sources/{eraser.png → one/eraser.png} +0 -0
  20. data/lib/montage/templates/sources/two/inbox-image.png +0 -0
  21. data/lib/montage/templates/sources/two/magnet.png +0 -0
  22. data/lib/montage/templates/sources/two/newspaper.png +0 -0
  23. data/lib/montage/templates/sources/two/television.png +0 -0
  24. data/lib/montage/templates/sources/two/wand-hat.png +0 -0
  25. data/lib/montage/templates/sources/two/wooden-box-label.png +0 -0
  26. data/lib/montage.rb +10 -1
  27. data/montage.gemspec +17 -34
  28. data/spec/lib/project_helper.rb +41 -6
  29. data/spec/lib/shared_project_specs.rb +10 -11
  30. data/spec/montage/commands/generate_spec.rb +86 -132
  31. data/spec/montage/commands/init_spec.rb +18 -43
  32. data/spec/montage/project_spec.rb +77 -63
  33. data/spec/montage/sass_builder_spec.rb +33 -57
  34. data/spec/montage/source_spec.rb +10 -31
  35. data/spec/montage/sprite_definition_spec.rb +361 -0
  36. data/spec/montage/sprite_spec.rb +58 -57
  37. metadata +31 -70
  38. data/spec/fixtures/custom_dirs/montage.yml +0 -8
  39. data/spec/fixtures/default/montage.yml +0 -7
  40. data/spec/fixtures/default/public/images/sprites/src/one.png +0 -0
  41. data/spec/fixtures/default/public/images/sprites/src/three.png +0 -0
  42. data/spec/fixtures/default/public/images/sprites/src/two.png +0 -0
  43. data/spec/fixtures/directory_config/config/montage.yml +0 -5
  44. data/spec/fixtures/missing_source/montage.yml +0 -3
  45. data/spec/fixtures/missing_source_dir/montage.yml +0 -5
  46. data/spec/fixtures/root_config/montage.yml +0 -5
  47. data/spec/fixtures/root_config/public/images/sprites/src/source_one.png +0 -0
  48. data/spec/fixtures/root_config/public/images/sprites/src/source_three.jpg +0 -0
  49. data/spec/fixtures/root_config/public/images/sprites/src/source_two +0 -0
  50. data/spec/fixtures/sources/hundred.png +0 -0
  51. data/spec/fixtures/sources/mammoth.png +0 -0
  52. data/spec/fixtures/sources/other.png +0 -0
  53. data/spec/fixtures/sources/twenty.png +0 -0
  54. data/spec/fixtures/subdirs/montage.yml +0 -5
  55. data/spec/fixtures/subdirs/sub/sub/keep +0 -0
  56. data/spec/lib/fixtures.rb +0 -7
@@ -2,34 +2,30 @@ module Montage
2
2
  # Represents a collection of images which will be used to make a sprite.
3
3
  #
4
4
  class Sprite
5
- attr_reader :name
5
+ attr_reader :name, :save_path, :url, :padding, :sources
6
6
 
7
7
  # Creates a new Sprite instance.
8
8
  #
9
9
  # @param [String] name
10
10
  # The name of the sprite. Will be used as the sprite filename (with an
11
11
  # extension added).
12
- # @param [Array<String>] sources
12
+ # @param [Array(String, Pathname)] sources
13
13
  # The name of each source image.
14
- # @param [Project] Project
14
+ # @param [Pathname] save_path
15
+ # The location at which the sprite should be saved.
16
+ # @param [Montage::Project] project
15
17
  # The project to which the sprite belongs.
18
+ # @param [Hash] options
19
+ # Extra options where you wish to override project defaults.
16
20
  #
17
- def initialize(name, sources, project)
18
- @name, @project = name, project
21
+ def initialize(name, sources, save_path, project, options = {})
22
+ @name = name
23
+ @save_path = save_path
19
24
 
20
- @sources =
21
- sources.inject(ActiveSupport::OrderedHash.new) do |hash, source|
22
- hash[source] = Source.new(@project.paths.sources, source, @name)
23
- hash
24
- end
25
- end
25
+ @padding = options.fetch(:padding, project.padding)
26
+ @url = options.fetch(:url, project.paths.url)
26
27
 
27
- # Returns an array of Source instances held by this Sprite.
28
- #
29
- # @return [Array<Source>]
30
- #
31
- def sources
32
- @sources.map { |_, source| source }
28
+ @sources = sources.map { |path| Source.new(path) }
33
29
  end
34
30
 
35
31
  # Returns an array of RMagick image instances; one for each source.
@@ -41,23 +37,15 @@ module Montage
41
37
  sources.map { |source| source.image }
42
38
  end
43
39
 
44
- # Returns the path to the sprite on disk.
45
- #
46
- # @return [Pathname]
47
- #
48
- def path
49
- @project.paths.sprites + "#{@name}.png"
50
- end
51
-
52
40
  # Returns the y-position of a given source.
53
41
  #
54
42
  # @return [Integer, Source]
55
43
  # The vertical position of the source image.
56
44
  #
57
45
  def position_of(source)
58
- source = source.name if source.is_a?(Source)
46
+ source = source.name if source.is_a?(Montage::Source)
59
47
 
60
- unless @sources.keys.include?(source)
48
+ unless sources.detect { |src| src.name == source }
61
49
  raise MissingSource,
62
50
  "Source image '#{source}' is not present in the '#{@name}' sprite"
63
51
  end
@@ -69,9 +57,9 @@ module Montage
69
57
  # generating CSS), it works out faster to fetch each source height
70
58
  # just once.
71
59
  @positions = {}
72
- @sources.inject(0) do |offset, (name, src)|
73
- @positions[name] = offset
74
- offset + src.image.rows + 20
60
+ @sources.inject(0) do |offset, src|
61
+ @positions[src.name] = offset
62
+ offset + src.image.rows + @padding
75
63
  end
76
64
  end
77
65
 
@@ -96,22 +84,22 @@ module Montage
96
84
  # Raised when the output directory can not be written to.
97
85
  #
98
86
  def write
99
- unless @project.paths.sprites.writable?
87
+ unless @save_path.dirname.writable?
100
88
  raise TargetNotWritable, <<-MESSAGE
101
- Montage can't save the sprite in `#{@project.paths.sprites.to_s}'
89
+ Montage can't save the sprite in `#{@save_path.dirname.to_s}'
102
90
  as it isn't writable.
103
91
  MESSAGE
104
92
  end
105
93
 
106
- list = sources.inject(Magick::ImageList.new) do |list, source|
94
+ list = @sources.inject(Magick::ImageList.new) do |list, source|
107
95
  list << source.image
108
- list << Magick::Image.new(1, @project.padding) do
96
+ list << Magick::Image.new(1, @padding) do
109
97
  self.background_color = '#FFF0'
110
98
  end
111
99
  end
112
100
 
113
101
  # RMagick uses instance_eval, @set isn't available in the block below.
114
- sources_length = sources.length
102
+ sources_length = @sources.length
115
103
 
116
104
  montage = list.montage do
117
105
  self.gravity = Magick::NorthWestGravity
@@ -124,8 +112,8 @@ module Montage
124
112
  end
125
113
 
126
114
  # Remove the blank space from the bottom of the image.
127
- montage.crop!(0, 0, 0, (montage.first.rows) - @project.padding)
128
- montage.write("PNG32:#{path}")
115
+ montage.crop!(0, 0, 0, (montage.first.rows) - @padding)
116
+ montage.write("PNG32:#{@save_path}")
129
117
  end
130
118
 
131
119
  end # Set
@@ -0,0 +1,127 @@
1
+ module Montage
2
+ # Represents a pseudo-file system path, where a directory can be replaced
3
+ # with the :sprite named segment. :name will match any directory -- all
4
+ # files with the same :name value will be placed into the same sprite file.
5
+ #
6
+ # Where a sprite source defines a :name segment, no sprite name needs to be
7
+ # explicitly set in the .montage file.
8
+ #
9
+ # For example, given the following directory structure:
10
+ #
11
+ # /path/to/something/
12
+ # big/
13
+ # one.png
14
+ # two.png
15
+ # small/
16
+ # three.png
17
+ # four.png
18
+ #
19
+ # ... then segmented path "/path/to/something/:name/*" will match all four
20
+ # PNG files, with "one" and "two" being placed in the "big" sprite, "three"
21
+ # and "four" in the "small" sprite.
22
+ #
23
+ class SpriteDefinition
24
+ # Creates a new SpriteDefinition instance.
25
+ #
26
+ # @param [Montage::Project] project
27
+ # @param [String, Pathname] path
28
+ # @param [Hash{String => Object}] options
29
+ #
30
+ def initialize(project, path, options = {})
31
+ @project = project
32
+ @path = project.paths.root + path
33
+
34
+ # Symbolize option keys.
35
+ @options = options.inject({}) do |opts, (key, value)|
36
+ opts[key.to_sym] = value ; opts
37
+ end
38
+
39
+ @options[:to] = (@project.paths.root +
40
+ (@options[:to] || Project::DEFAULTS[:to])).to_s
41
+
42
+ @options[:url] ||= project.paths.url
43
+ @options[:padding] ||= project.padding
44
+
45
+ if has_name_segment? and @options.has_key?(:name)
46
+ raise Montage::DuplicateName, <<-ERROR.compress_lines
47
+ Sprite `#{path}' has both a :name path segment and a "name"
48
+ option; please use only one.
49
+ ERROR
50
+ elsif not has_name_segment? and not @options.has_key?(:name)
51
+ raise Montage::MissingName, <<-ERROR.compress_lines
52
+ Sprite `#{path}' requires a name. Add a :name path segment
53
+ or add a "name" option.
54
+ ERROR
55
+ elsif has_name_segment? and not @options[:to] =~ /:name/
56
+ raise Montage::MissingName, <<-ERROR.compress_lines
57
+ Sprite `#{path}' requires :name in the "to" option.
58
+ ERROR
59
+ end
60
+ end
61
+
62
+ # Returns an array of Sprites defined.
63
+ #
64
+ # @return [Array(Montage::Sprite)]
65
+ #
66
+ def to_sprites
67
+ matching_sources.map do |sprite_name, sources|
68
+ save_path = Pathname.new(@options[:to].gsub(/:name/, sprite_name))
69
+
70
+ url = @options[:url].dup # Since it may be the DEFAULT string
71
+ url.gsub!(/:name/, sprite_name)
72
+ url.gsub!(/:filename/, save_path.basename.to_s)
73
+
74
+ Montage::Sprite.new(sprite_name, sources, save_path, @project,
75
+ :url => url,
76
+ :padding => @options[:padding]
77
+ )
78
+ end
79
+ end
80
+
81
+ private # ================================================================
82
+
83
+ # Returns whether the path has a :name segment.
84
+ #
85
+ # @return [Boolean]
86
+ #
87
+ def has_name_segment?
88
+ @path.to_s =~ /:name/
89
+ end
90
+
91
+ # Returns a Hash containing source files which can be used when creating
92
+ # Sprites. Each key is sprite name with each value the path to a matching
93
+ # source file. When a SpriteDefinition doesn't have a :name segment, the
94
+ # Hash will contain a single key: nil.
95
+ #
96
+ # @return[Hash{String => Array(Pathname)}]
97
+ #
98
+ def matching_sources
99
+ @matching_sources ||= begin
100
+ if not has_name_segment?
101
+ { @options[:name] => Pathname.glob(@path.to_s) }
102
+ else
103
+ regexp = Regexp.escape(@path.to_s)
104
+ regexp.gsub!(/\\\*\\\*/, '.+')
105
+ regexp.gsub!(/\\\*/, '[^\\/]+')
106
+ regexp.gsub!(/:name/, '([^\\/]+)')
107
+
108
+ # Replace OR globs ({png,jpg,etc}).
109
+ regexp.gsub!(/\\\{([^\\\}]+)\\\}/) do |found|
110
+ "(?:#{found[2..-4].split(',').join('|')})"
111
+ end
112
+
113
+ all_files = Pathname.glob(@path.to_s.gsub(/:name/, '*'))
114
+ all_files.inject({}) do |sources, file|
115
+ if file.file? && match = file.to_s.match(regexp)
116
+ sources[match[1]] ||= []
117
+ sources[match[1]] << file
118
+ end
119
+
120
+ sources
121
+ end
122
+ end
123
+ end # begin
124
+ end # matching_sources
125
+
126
+ end # SpriteDefinition
127
+ end # Montage
@@ -1,26 +1,36 @@
1
1
  ---
2
2
 
3
- # If you need to specify non-standard locations for the source
4
- # files, or the output locations for the sprites or SASS, change
5
- # the relevant option below. Directories are relative to the
6
- # project root unless they have a leading slash.
3
+ config.root: "."
4
+ config.sass: "public/stylesheets/sass"
5
+ config.url: "/images/:filename"
7
6
 
8
- config.sources: <sources>
9
- config.sprites: <sprites>
10
- config.sass: "public/stylesheets/sass"
11
- config.sprite_url: "/images/sprites"
7
+ # --------------------------------------------------------------
12
8
 
13
- # --------------------------------------------------------------------------
9
+ # The sample definition below will search each sub-directory in
10
+ # the sources directory; a sprite will be created for each sub-
11
+ # directory containing the png, jpg, and gif files.
12
+ #
13
+ # All paths are relative to the project root file, unless they
14
+ # begin with a / in which case they are absolute. Add as many
15
+ # sprite definitions as you need.
14
16
 
15
- # The sample below will produce two sprites (one.png and two.png) with the
16
- # specified source images. You can omit file extensions.
17
+ "<sources>/:name/*.{png,jpg,jpeg,gif}":
18
+ to: "<sprites>/:name.png"
17
19
 
18
- one:
19
- - book
20
- - box-label
21
- - calculator
20
+ # You can override any of the default settings on a per-sprite
21
+ # basis. For example... (these are the defaults)
22
22
 
23
- two:
24
- - calendar-month
25
- - camera
26
- - eraser
23
+ # "public/images/sprites/src/:name/*.{png,jpg,jpeg,gif}":
24
+ # to: "public/images/:name.png"
25
+ #
26
+ # # The directory in which the sprite(s) are saved relative to
27
+ # # the web-root (used in Sass files to locate the image).
28
+ # url: "/images/:filename"
29
+ #
30
+ # # Puts 20 pixels of space between each source image.
31
+ # padding: 20
32
+
33
+ # # Alternatively, change the default settings for all sprites:
34
+ #
35
+ # config.url: "/omicron_persei_8/sprites"
36
+ # config.sass: false
@@ -8,7 +8,7 @@
8
8
  @<%= index == 0 ? '' : 'else ' %>if $icon == "<%= source.name %>"
9
9
  $y_offset: $y_offset - <%= sprite.position_of(source) %>px
10
10
  <% end %>
11
- background: url(<%= @project.paths.url + "/#{sprite.name}.png" %>) $x_offset $y_offset no-repeat
11
+ background: url(<%= sprite.url %>) $x_offset $y_offset no-repeat
12
12
 
13
13
  =<%= sprite.name %>-sprite-pos($icon, $x_offset: 0px, $y_offset: 0px)
14
14
  <% sprite.sources.each_with_index do |source, index| %>
data/lib/montage.rb CHANGED
@@ -4,7 +4,6 @@ require 'pathname'
4
4
  require 'yaml'
5
5
 
6
6
  # Gems.
7
- require 'active_support/ordered_hash'
8
7
  require 'rmagick'
9
8
 
10
9
  # On with the library...
@@ -13,6 +12,7 @@ require 'montage/project'
13
12
  require 'montage/sass_builder'
14
13
  require 'montage/source'
15
14
  require 'montage/sprite'
15
+ require 'montage/sprite_definition'
16
16
  require 'montage/version'
17
17
 
18
18
  module Montage
@@ -30,4 +30,13 @@ module Montage
30
30
 
31
31
  # Raised when a sprite can't be saved due to incorrect permissions.
32
32
  TargetNotWritable = Class.new(MontageError)
33
+
34
+ # Raised when a sprite defintion doesn't include a name.
35
+ MissingName = Class.new(MontageError)
36
+
37
+ # Raised when a sprite defines a :name path segment, and a name option.
38
+ DuplicateName = Class.new(MontageError)
39
+
40
+ # Raised when a sprite definition doesn't have a to option.
41
+ MissingTo = Class.new(MontageError)
33
42
  end
data/montage.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{montage}
8
- s.version = "0.2.1"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Anthony Williams"]
12
- s.date = %q{2010-04-08}
12
+ s.date = %q{2010-04-12}
13
13
  s.default_executable = %q{montage}
14
14
  s.description = %q{Even Rocky had a montage.}
15
15
  s.email = %q{hi@antw.me}
@@ -36,36 +36,24 @@ Gem::Specification.new do |s|
36
36
  "lib/montage/sass_builder.rb",
37
37
  "lib/montage/source.rb",
38
38
  "lib/montage/sprite.rb",
39
+ "lib/montage/sprite_definition.rb",
39
40
  "lib/montage/templates/montage.yml",
40
41
  "lib/montage/templates/sass_mixins.erb",
41
- "lib/montage/templates/sources/book.png",
42
- "lib/montage/templates/sources/box-label.png",
43
- "lib/montage/templates/sources/calculator.png",
44
- "lib/montage/templates/sources/calendar-month.png",
45
- "lib/montage/templates/sources/camera.png",
46
- "lib/montage/templates/sources/eraser.png",
42
+ "lib/montage/templates/sources/one/book.png",
43
+ "lib/montage/templates/sources/one/box-label.png",
44
+ "lib/montage/templates/sources/one/calculator.png",
45
+ "lib/montage/templates/sources/one/calendar-month.png",
46
+ "lib/montage/templates/sources/one/camera.png",
47
+ "lib/montage/templates/sources/one/eraser.png",
48
+ "lib/montage/templates/sources/two/inbox-image.png",
49
+ "lib/montage/templates/sources/two/magnet.png",
50
+ "lib/montage/templates/sources/two/newspaper.png",
51
+ "lib/montage/templates/sources/two/television.png",
52
+ "lib/montage/templates/sources/two/wand-hat.png",
53
+ "lib/montage/templates/sources/two/wooden-box-label.png",
47
54
  "lib/montage/version.rb",
48
55
  "montage.gemspec",
49
- "spec/fixtures/custom_dirs/montage.yml",
50
- "spec/fixtures/default/montage.yml",
51
- "spec/fixtures/default/public/images/sprites/src/one.png",
52
- "spec/fixtures/default/public/images/sprites/src/three.png",
53
- "spec/fixtures/default/public/images/sprites/src/two.png",
54
- "spec/fixtures/directory_config/config/montage.yml",
55
- "spec/fixtures/missing_source/montage.yml",
56
- "spec/fixtures/missing_source_dir/montage.yml",
57
- "spec/fixtures/root_config/montage.yml",
58
- "spec/fixtures/root_config/public/images/sprites/src/source_one.png",
59
- "spec/fixtures/root_config/public/images/sprites/src/source_three.jpg",
60
- "spec/fixtures/root_config/public/images/sprites/src/source_two",
61
- "spec/fixtures/sources/hundred.png",
62
- "spec/fixtures/sources/mammoth.png",
63
- "spec/fixtures/sources/other.png",
64
- "spec/fixtures/sources/twenty.png",
65
- "spec/fixtures/subdirs/montage.yml",
66
- "spec/fixtures/subdirs/sub/sub/keep",
67
56
  "spec/lib/command_runner.rb",
68
- "spec/lib/fixtures.rb",
69
57
  "spec/lib/have_public_method_defined.rb",
70
58
  "spec/lib/project_helper.rb",
71
59
  "spec/lib/shared_project_specs.rb",
@@ -77,6 +65,7 @@ Gem::Specification.new do |s|
77
65
  "spec/montage/sass_builder_spec.rb",
78
66
  "spec/montage/source_spec.rb",
79
67
  "spec/montage/spec/have_public_method_defined_spec.rb",
68
+ "spec/montage/sprite_definition_spec.rb",
80
69
  "spec/montage/sprite_spec.rb",
81
70
  "spec/rcov.opts",
82
71
  "spec/spec.opts",
@@ -92,7 +81,6 @@ Gem::Specification.new do |s|
92
81
  s.summary = %q{Montage}
93
82
  s.test_files = [
94
83
  "spec/lib/command_runner.rb",
95
- "spec/lib/fixtures.rb",
96
84
  "spec/lib/have_public_method_defined.rb",
97
85
  "spec/lib/project_helper.rb",
98
86
  "spec/lib/shared_project_specs.rb",
@@ -104,6 +92,7 @@ Gem::Specification.new do |s|
104
92
  "spec/montage/sass_builder_spec.rb",
105
93
  "spec/montage/source_spec.rb",
106
94
  "spec/montage/spec/have_public_method_defined_spec.rb",
95
+ "spec/montage/sprite_definition_spec.rb",
107
96
  "spec/montage/sprite_spec.rb",
108
97
  "spec/spec_helper.rb"
109
98
  ]
@@ -113,30 +102,24 @@ Gem::Specification.new do |s|
113
102
  s.specification_version = 3
114
103
 
115
104
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
116
- s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0.beta"])
117
105
  s.add_runtime_dependency(%q<rmagick>, [">= 2.12"])
118
106
  s.add_runtime_dependency(%q<highline>, [">= 1.5"])
119
107
  s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
120
- s.add_development_dependency(%q<cucumber>, [">= 0.6"])
121
108
  s.add_development_dependency(%q<open4>, [">= 1.0"])
122
109
  s.add_development_dependency(%q<haml>, [">= 3.0.0.beta.1"])
123
110
  s.add_development_dependency(%q<yard>, [">= 0.5"])
124
111
  else
125
- s.add_dependency(%q<activesupport>, [">= 3.0.0.beta"])
126
112
  s.add_dependency(%q<rmagick>, [">= 2.12"])
127
113
  s.add_dependency(%q<highline>, [">= 1.5"])
128
114
  s.add_dependency(%q<rspec>, [">= 1.3.0"])
129
- s.add_dependency(%q<cucumber>, [">= 0.6"])
130
115
  s.add_dependency(%q<open4>, [">= 1.0"])
131
116
  s.add_dependency(%q<haml>, [">= 3.0.0.beta.1"])
132
117
  s.add_dependency(%q<yard>, [">= 0.5"])
133
118
  end
134
119
  else
135
- s.add_dependency(%q<activesupport>, [">= 3.0.0.beta"])
136
120
  s.add_dependency(%q<rmagick>, [">= 2.12"])
137
121
  s.add_dependency(%q<highline>, [">= 1.5"])
138
122
  s.add_dependency(%q<rspec>, [">= 1.3.0"])
139
- s.add_dependency(%q<cucumber>, [">= 0.6"])
140
123
  s.add_dependency(%q<open4>, [">= 1.0"])
141
124
  s.add_dependency(%q<haml>, [">= 3.0.0.beta.1"])
142
125
  s.add_dependency(%q<yard>, [">= 0.5"])
@@ -34,8 +34,8 @@ module Montage
34
34
  self.class.cleanup!
35
35
  project_dir.mkpath
36
36
 
37
- self.sources_path = "public/images/sprites/src"
38
- self.sprites_path = "public/images/sprites"
37
+ self.sources_path = "public/images/sprites"
38
+ self.sprites_path = "public/images"
39
39
  end
40
40
 
41
41
  def sources_path=(path)
@@ -86,17 +86,40 @@ module Montage
86
86
 
87
87
  # --- File Writers -----------------------------------------------------
88
88
 
89
- # Writes montage.yml file in the project root with the given contents.
89
+ # Writes .montage file in the project root with the given contents.
90
90
  #
91
+ # @param [String] to
92
+ # The path at which to save the config file. Or: The file contents if
93
+ # you want to save at the default location.
91
94
  # @param [String] contents
92
95
  # The contents to be saved as the config file.
93
96
  #
94
- def write_config(contents)
95
- File.open(project_dir + 'montage.yml', 'w') do |file|
97
+ def write_config(to, contents = nil)
98
+ if contents.nil?
99
+ # Sigh; if only 1.9 was more popular...
100
+ contents, to = to, '.montage'
101
+ else
102
+ (project_dir + to).dirname.mkpath
103
+ end
104
+
105
+ File.open(project_dir + to, 'w') do |file|
96
106
  file.puts contents.unindent
97
107
  end
98
108
  end
99
109
 
110
+ # Writes a simple config file.
111
+ #
112
+ # @param [String] to
113
+ # The path at which to save the config file.
114
+ #
115
+ def write_simple_config(to = '.montage')
116
+ write_config to, <<-CONFIG
117
+ ---
118
+ "public/images/sprites/:name/*.{png,jpg,jpeg,gif}":
119
+ to: "public/images/:name.png"
120
+ CONFIG
121
+ end
122
+
100
123
  # Writes a source image file to the src directory.
101
124
  #
102
125
  # @param [String] name
@@ -123,13 +146,25 @@ module Montage
123
146
 
124
147
  # Creates a directory in the project.
125
148
  #
126
- # @param [String] dir
149
+ # @param [String] path
127
150
  # Path to the directory, relative to the project root.
128
151
  #
129
152
  def mkdir(path)
130
153
  (project_dir + path).mkpath
131
154
  end
132
155
 
156
+ # Creates an empty file.
157
+ #
158
+ # @param [String] path
159
+ # Path to the file to be touched.
160
+ #
161
+ def touch(*paths)
162
+ paths.each do |path|
163
+ (project_dir + path).dirname.mkpath
164
+ FileUtils.touch(project_dir + path)
165
+ end
166
+ end
167
+
133
168
  end # ProjectHelper
134
169
  end # Spec
135
170
  end # Montage
@@ -2,9 +2,16 @@ describe 'a project with correct paths', :shared => true do
2
2
  # Requires:
3
3
  #
4
4
  # @project => Montage::Project
5
- # @root => Pathname (path to project root)
5
+ # @helper => Montage::Spec::ProjectHelper
6
6
  # @config => Pathname (path to config file)
7
7
  #
8
+ # (optional)
9
+ # @root => Pathname (path to the root of the project)
10
+ #
11
+
12
+ before(:all) do
13
+ @root ||= @helper.project_dir
14
+ end
8
15
 
9
16
  it 'should set the project root path' do
10
17
  @project.paths.root.should == @root
@@ -14,19 +21,11 @@ describe 'a project with correct paths', :shared => true do
14
21
  @project.paths.config.should == @config
15
22
  end
16
23
 
17
- it 'should set the sources path' do
18
- @project.paths.sources.should == @root + 'public/images/sprites/src'
19
- end
20
-
21
- it 'should set the sprite path' do
22
- @project.paths.sprites.should == @root + 'public/images/sprites'
23
- end
24
-
25
24
  it 'should set the SASS output path' do
26
25
  @project.paths.sass.should == @root + 'public/stylesheets/sass'
27
26
  end
28
27
 
29
28
  it 'should set the CSS sprite URL' do
30
- @project.paths.url.should == '/images/sprites'
29
+ @project.paths.url.should == '/images/:name.png'
31
30
  end
32
- end
31
+ end