haml 3.1.0.alpha.14 → 3.1.0.alpha.17

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

Files changed (222) hide show
  1. data/EDGE_GEM_VERSION +1 -1
  2. data/VERSION +1 -1
  3. data/lib/haml.rb +3 -2
  4. data/lib/haml/exec.rb +0 -226
  5. data/lib/sass.rb +8 -0
  6. data/lib/sass/plugin.rb +8 -0
  7. data/lib/sass/rails2_shim.rb +9 -0
  8. data/lib/sass/rails3_shim.rb +16 -0
  9. data/vendor/sass/CONTRIBUTING +3 -0
  10. data/vendor/sass/MIT-LICENSE +20 -0
  11. data/vendor/sass/README.md +201 -0
  12. data/vendor/sass/Rakefile +363 -0
  13. data/vendor/sass/TODO +39 -0
  14. data/vendor/sass/VERSION +1 -0
  15. data/vendor/sass/VERSION_NAME +1 -0
  16. data/vendor/sass/bin/css2sass +13 -0
  17. data/vendor/sass/bin/sass +8 -0
  18. data/vendor/sass/bin/sass-convert +7 -0
  19. data/vendor/sass/doc-src/FAQ.md +35 -0
  20. data/vendor/sass/doc-src/INDENTED_SYNTAX.md +210 -0
  21. data/vendor/sass/doc-src/SASS_CHANGELOG.md +1878 -0
  22. data/vendor/sass/doc-src/SASS_REFERENCE.md +1713 -0
  23. data/vendor/sass/doc-src/SCSS_FOR_SASS_USERS.md +155 -0
  24. data/vendor/sass/ext/extconf.rb +10 -0
  25. data/vendor/sass/extra/update_watch.rb +13 -0
  26. data/vendor/sass/init.rb +18 -0
  27. data/vendor/sass/lib/sass.rb +71 -0
  28. data/vendor/sass/lib/sass/cache_store.rb +208 -0
  29. data/vendor/sass/lib/sass/callbacks.rb +66 -0
  30. data/vendor/sass/lib/sass/css.rb +294 -0
  31. data/vendor/sass/lib/sass/engine.rb +792 -0
  32. data/vendor/sass/lib/sass/environment.rb +143 -0
  33. data/vendor/sass/lib/sass/error.rb +201 -0
  34. data/vendor/sass/lib/sass/exec.rb +619 -0
  35. data/vendor/sass/lib/sass/importers.rb +22 -0
  36. data/vendor/sass/lib/sass/importers/base.rb +138 -0
  37. data/vendor/sass/lib/sass/importers/filesystem.rb +121 -0
  38. data/vendor/sass/lib/sass/less.rb +363 -0
  39. data/vendor/sass/lib/sass/plugin.rb +126 -0
  40. data/vendor/sass/lib/sass/plugin/compiler.rb +346 -0
  41. data/vendor/sass/lib/sass/plugin/configuration.rb +123 -0
  42. data/vendor/sass/lib/sass/plugin/generic.rb +15 -0
  43. data/vendor/sass/lib/sass/plugin/merb.rb +48 -0
  44. data/vendor/sass/lib/sass/plugin/rack.rb +47 -0
  45. data/vendor/sass/lib/sass/plugin/rails.rb +41 -0
  46. data/vendor/sass/lib/sass/plugin/staleness_checker.rb +145 -0
  47. data/vendor/sass/lib/sass/railtie.rb +8 -0
  48. data/vendor/sass/lib/sass/repl.rb +58 -0
  49. data/vendor/sass/lib/sass/root.rb +7 -0
  50. data/vendor/sass/lib/sass/script.rb +63 -0
  51. data/vendor/sass/lib/sass/script/bool.rb +18 -0
  52. data/vendor/sass/lib/sass/script/color.rb +491 -0
  53. data/vendor/sass/lib/sass/script/css_lexer.rb +29 -0
  54. data/vendor/sass/lib/sass/script/css_parser.rb +31 -0
  55. data/vendor/sass/lib/sass/script/funcall.rb +76 -0
  56. data/vendor/sass/lib/sass/script/functions.rb +852 -0
  57. data/vendor/sass/lib/sass/script/interpolation.rb +70 -0
  58. data/vendor/sass/lib/sass/script/lexer.rb +337 -0
  59. data/vendor/sass/lib/sass/script/literal.rb +236 -0
  60. data/vendor/sass/lib/sass/script/node.rb +112 -0
  61. data/vendor/sass/lib/sass/script/number.rb +423 -0
  62. data/vendor/sass/lib/sass/script/operation.rb +90 -0
  63. data/vendor/sass/lib/sass/script/parser.rb +392 -0
  64. data/vendor/sass/lib/sass/script/string.rb +67 -0
  65. data/vendor/sass/lib/sass/script/string_interpolation.rb +93 -0
  66. data/vendor/sass/lib/sass/script/unary_operation.rb +57 -0
  67. data/vendor/sass/lib/sass/script/variable.rb +48 -0
  68. data/vendor/sass/lib/sass/scss.rb +17 -0
  69. data/vendor/sass/lib/sass/scss/css_parser.rb +51 -0
  70. data/vendor/sass/lib/sass/scss/parser.rb +838 -0
  71. data/vendor/sass/lib/sass/scss/rx.rb +126 -0
  72. data/vendor/sass/lib/sass/scss/sass_parser.rb +11 -0
  73. data/vendor/sass/lib/sass/scss/script_lexer.rb +15 -0
  74. data/vendor/sass/lib/sass/scss/script_parser.rb +25 -0
  75. data/vendor/sass/lib/sass/scss/static_parser.rb +40 -0
  76. data/vendor/sass/lib/sass/selector.rb +361 -0
  77. data/vendor/sass/lib/sass/selector/abstract_sequence.rb +62 -0
  78. data/vendor/sass/lib/sass/selector/comma_sequence.rb +82 -0
  79. data/vendor/sass/lib/sass/selector/sequence.rb +236 -0
  80. data/vendor/sass/lib/sass/selector/simple.rb +113 -0
  81. data/vendor/sass/lib/sass/selector/simple_sequence.rb +135 -0
  82. data/vendor/sass/lib/sass/shared.rb +78 -0
  83. data/vendor/sass/lib/sass/tree/comment_node.rb +128 -0
  84. data/vendor/sass/lib/sass/tree/debug_node.rb +36 -0
  85. data/vendor/sass/lib/sass/tree/directive_node.rb +75 -0
  86. data/vendor/sass/lib/sass/tree/extend_node.rb +65 -0
  87. data/vendor/sass/lib/sass/tree/for_node.rb +67 -0
  88. data/vendor/sass/lib/sass/tree/if_node.rb +81 -0
  89. data/vendor/sass/lib/sass/tree/import_node.rb +124 -0
  90. data/vendor/sass/lib/sass/tree/mixin_def_node.rb +60 -0
  91. data/vendor/sass/lib/sass/tree/mixin_node.rb +123 -0
  92. data/vendor/sass/lib/sass/tree/node.rb +490 -0
  93. data/vendor/sass/lib/sass/tree/prop_node.rb +220 -0
  94. data/vendor/sass/lib/sass/tree/root_node.rb +125 -0
  95. data/vendor/sass/lib/sass/tree/rule_node.rb +273 -0
  96. data/vendor/sass/lib/sass/tree/variable_node.rb +39 -0
  97. data/vendor/sass/lib/sass/tree/warn_node.rb +42 -0
  98. data/vendor/sass/lib/sass/tree/while_node.rb +48 -0
  99. data/vendor/sass/lib/sass/util.rb +700 -0
  100. data/vendor/sass/lib/sass/util/subset_map.rb +101 -0
  101. data/vendor/sass/lib/sass/version.rb +109 -0
  102. data/vendor/sass/rails/init.rb +1 -0
  103. data/vendor/sass/sass.gemspec +32 -0
  104. data/vendor/sass/test/sass/cache_test.rb +74 -0
  105. data/vendor/sass/test/sass/callbacks_test.rb +61 -0
  106. data/vendor/sass/test/sass/conversion_test.rb +1210 -0
  107. data/vendor/sass/test/sass/css2sass_test.rb +364 -0
  108. data/vendor/sass/test/sass/data/hsl-rgb.txt +319 -0
  109. data/vendor/sass/test/sass/engine_test.rb +2305 -0
  110. data/vendor/sass/test/sass/extend_test.rb +1348 -0
  111. data/vendor/sass/test/sass/functions_test.rb +565 -0
  112. data/vendor/sass/test/sass/importer_test.rb +104 -0
  113. data/vendor/sass/test/sass/less_conversion_test.rb +632 -0
  114. data/vendor/sass/test/sass/mock_importer.rb +49 -0
  115. data/vendor/sass/test/sass/more_results/more1.css +9 -0
  116. data/vendor/sass/test/sass/more_results/more1_with_line_comments.css +26 -0
  117. data/vendor/sass/test/sass/more_results/more_import.css +29 -0
  118. data/vendor/sass/test/sass/more_templates/_more_partial.sass +2 -0
  119. data/vendor/sass/test/sass/more_templates/more1.sass +23 -0
  120. data/vendor/sass/test/sass/more_templates/more_import.sass +11 -0
  121. data/vendor/sass/test/sass/plugin_test.rb +430 -0
  122. data/vendor/sass/test/sass/results/alt.css +4 -0
  123. data/vendor/sass/test/sass/results/basic.css +9 -0
  124. data/vendor/sass/test/sass/results/compact.css +5 -0
  125. data/vendor/sass/test/sass/results/complex.css +86 -0
  126. data/vendor/sass/test/sass/results/compressed.css +1 -0
  127. data/vendor/sass/test/sass/results/expanded.css +19 -0
  128. data/vendor/sass/test/sass/results/import.css +31 -0
  129. data/vendor/sass/test/sass/results/line_numbers.css +49 -0
  130. data/vendor/sass/test/sass/results/mixins.css +95 -0
  131. data/vendor/sass/test/sass/results/multiline.css +24 -0
  132. data/vendor/sass/test/sass/results/nested.css +22 -0
  133. data/vendor/sass/test/sass/results/options.css +1 -0
  134. data/vendor/sass/test/sass/results/parent_ref.css +13 -0
  135. data/vendor/sass/test/sass/results/script.css +16 -0
  136. data/vendor/sass/test/sass/results/scss_import.css +31 -0
  137. data/vendor/sass/test/sass/results/scss_importee.css +2 -0
  138. data/vendor/sass/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  139. data/vendor/sass/test/sass/results/subdir/subdir.css +3 -0
  140. data/vendor/sass/test/sass/results/units.css +11 -0
  141. data/vendor/sass/test/sass/results/warn.css +0 -0
  142. data/vendor/sass/test/sass/results/warn_imported.css +0 -0
  143. data/vendor/sass/test/sass/script_conversion_test.rb +254 -0
  144. data/vendor/sass/test/sass/script_test.rb +470 -0
  145. data/vendor/sass/test/sass/scss/css_test.rb +897 -0
  146. data/vendor/sass/test/sass/scss/rx_test.rb +156 -0
  147. data/vendor/sass/test/sass/scss/scss_test.rb +1088 -0
  148. data/vendor/sass/test/sass/scss/test_helper.rb +37 -0
  149. data/vendor/sass/test/sass/templates/_partial.sass +2 -0
  150. data/vendor/sass/test/sass/templates/alt.sass +16 -0
  151. data/vendor/sass/test/sass/templates/basic.sass +23 -0
  152. data/vendor/sass/test/sass/templates/bork1.sass +2 -0
  153. data/vendor/sass/test/sass/templates/bork2.sass +2 -0
  154. data/vendor/sass/test/sass/templates/bork3.sass +2 -0
  155. data/vendor/sass/test/sass/templates/bork4.sass +2 -0
  156. data/vendor/sass/test/sass/templates/compact.sass +17 -0
  157. data/vendor/sass/test/sass/templates/complex.sass +305 -0
  158. data/vendor/sass/test/sass/templates/compressed.sass +15 -0
  159. data/vendor/sass/test/sass/templates/expanded.sass +17 -0
  160. data/vendor/sass/test/sass/templates/import.sass +12 -0
  161. data/vendor/sass/test/sass/templates/importee.less +2 -0
  162. data/vendor/sass/test/sass/templates/importee.sass +19 -0
  163. data/vendor/sass/test/sass/templates/line_numbers.sass +13 -0
  164. data/vendor/sass/test/sass/templates/mixin_bork.sass +5 -0
  165. data/vendor/sass/test/sass/templates/mixins.sass +76 -0
  166. data/vendor/sass/test/sass/templates/multiline.sass +20 -0
  167. data/vendor/sass/test/sass/templates/nested.sass +25 -0
  168. data/vendor/sass/test/sass/templates/nested_bork1.sass +2 -0
  169. data/vendor/sass/test/sass/templates/nested_bork2.sass +2 -0
  170. data/vendor/sass/test/sass/templates/nested_bork3.sass +2 -0
  171. data/vendor/sass/test/sass/templates/nested_bork4.sass +2 -0
  172. data/vendor/sass/test/sass/templates/nested_mixin_bork.sass +6 -0
  173. data/vendor/sass/test/sass/templates/options.sass +2 -0
  174. data/vendor/sass/test/sass/templates/parent_ref.sass +25 -0
  175. data/vendor/sass/test/sass/templates/script.sass +101 -0
  176. data/vendor/sass/test/sass/templates/scss_import.scss +11 -0
  177. data/vendor/sass/test/sass/templates/scss_importee.scss +1 -0
  178. data/vendor/sass/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  179. data/vendor/sass/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  180. data/vendor/sass/test/sass/templates/subdir/subdir.sass +6 -0
  181. data/vendor/sass/test/sass/templates/units.sass +11 -0
  182. data/vendor/sass/test/sass/templates/warn.sass +3 -0
  183. data/vendor/sass/test/sass/templates/warn_imported.sass +4 -0
  184. data/vendor/sass/test/sass/test_helper.rb +8 -0
  185. data/vendor/sass/test/sass/util/subset_map_test.rb +91 -0
  186. data/vendor/sass/test/sass/util_test.rb +275 -0
  187. data/vendor/sass/test/test_helper.rb +64 -0
  188. data/vendor/sass/vendor/fssm/LICENSE +20 -0
  189. data/vendor/sass/vendor/fssm/README.markdown +55 -0
  190. data/vendor/sass/vendor/fssm/Rakefile +59 -0
  191. data/vendor/sass/vendor/fssm/VERSION.yml +5 -0
  192. data/vendor/sass/vendor/fssm/example.rb +9 -0
  193. data/vendor/sass/vendor/fssm/fssm.gemspec +77 -0
  194. data/vendor/sass/vendor/fssm/lib/fssm.rb +33 -0
  195. data/vendor/sass/vendor/fssm/lib/fssm/backends/fsevents.rb +36 -0
  196. data/vendor/sass/vendor/fssm/lib/fssm/backends/inotify.rb +26 -0
  197. data/vendor/sass/vendor/fssm/lib/fssm/backends/polling.rb +25 -0
  198. data/vendor/sass/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +131 -0
  199. data/vendor/sass/vendor/fssm/lib/fssm/monitor.rb +26 -0
  200. data/vendor/sass/vendor/fssm/lib/fssm/path.rb +91 -0
  201. data/vendor/sass/vendor/fssm/lib/fssm/pathname.rb +502 -0
  202. data/vendor/sass/vendor/fssm/lib/fssm/state/directory.rb +57 -0
  203. data/vendor/sass/vendor/fssm/lib/fssm/state/file.rb +24 -0
  204. data/vendor/sass/vendor/fssm/lib/fssm/support.rb +63 -0
  205. data/vendor/sass/vendor/fssm/lib/fssm/tree.rb +176 -0
  206. data/vendor/sass/vendor/fssm/profile/prof-cache.rb +40 -0
  207. data/vendor/sass/vendor/fssm/profile/prof-fssm-pathname.html +1231 -0
  208. data/vendor/sass/vendor/fssm/profile/prof-pathname.rb +68 -0
  209. data/vendor/sass/vendor/fssm/profile/prof-plain-pathname.html +988 -0
  210. data/vendor/sass/vendor/fssm/profile/prof.html +2379 -0
  211. data/vendor/sass/vendor/fssm/spec/path_spec.rb +75 -0
  212. data/vendor/sass/vendor/fssm/spec/root/duck/quack.txt +0 -0
  213. data/vendor/sass/vendor/fssm/spec/root/file.css +0 -0
  214. data/vendor/sass/vendor/fssm/spec/root/file.rb +0 -0
  215. data/vendor/sass/vendor/fssm/spec/root/file.yml +0 -0
  216. data/vendor/sass/vendor/fssm/spec/root/moo/cow.txt +0 -0
  217. data/vendor/sass/vendor/fssm/spec/spec_helper.rb +14 -0
  218. data/vendor/sass/yard/callbacks.rb +29 -0
  219. data/vendor/sass/yard/default/fulldoc/html/css/common.sass +26 -0
  220. data/vendor/sass/yard/default/layout/html/footer.erb +12 -0
  221. data/vendor/sass/yard/inherited_hash.rb +41 -0
  222. metadata +219 -2
@@ -0,0 +1,22 @@
1
+ module Sass
2
+ # Sass importers are in charge of taking paths passed to `@import`
3
+ # and finding the appropriate Sass code for those paths.
4
+ # By default, this code is always loaded from the filesystem,
5
+ # but importers could be added to load from a database or over HTTP.
6
+ #
7
+ # Each importer is in charge of a single load path
8
+ # (or whatever the corresponding notion is for the backend).
9
+ # Importers can be placed in the {file:SASS_REFERENCE.md#load_paths-option `:load_paths` array}
10
+ # alongside normal filesystem paths.
11
+ #
12
+ # When resolving an `@import`, Sass will go through the load paths
13
+ # looking for an importer that successfully imports the path.
14
+ # Once one is found, the imported file is used.
15
+ #
16
+ # User-created importers must inherit from {Importers::Base}.
17
+ module Importers
18
+ end
19
+ end
20
+
21
+ require 'sass/importers/base'
22
+ require 'sass/importers/filesystem'
@@ -0,0 +1,138 @@
1
+ module Sass
2
+ module Importers
3
+ # The abstract base class for Sass importers.
4
+ # All importers should inherit from this.
5
+ #
6
+ # At the most basic level, an importer is given a string
7
+ # and must return a {Sass::Engine} containing some Sass code.
8
+ # This string can be interpreted however the importer wants;
9
+ # however, subclasses are encouraged to use the URI format
10
+ # for pathnames.
11
+ #
12
+ # Importers that have some notion of "relative imports"
13
+ # should take a single load path in their constructor,
14
+ # and interpret paths as relative to that.
15
+ # They should also implement the \{#find\_relative} method.
16
+ #
17
+ # Importers should be serializable via `Marshal.dump`.
18
+ # In addition to the standard `_dump` and `_load` methods,
19
+ # importers can define `_before_dump`, `_after_dump`, `_around_dump`,
20
+ # and `_after_load` methods as per {Sass::Util#dump} and {Sass::Util#load}.
21
+ #
22
+ # @abstract
23
+ class Base
24
+
25
+ # Find a Sass file relative to another file.
26
+ # Importers without a notion of "relative paths"
27
+ # should just return nil here.
28
+ #
29
+ # If the importer does have a notion of "relative paths",
30
+ # it should ignore its load path during this method.
31
+ #
32
+ # See \{#find} for important information on how this method should behave.
33
+ #
34
+ # The `:filename` option passed to the returned {Sass::Engine}
35
+ # should be of a format that could be passed to \{#find}.
36
+ #
37
+ # @param uri [String] The URI to import. This is not necessarily relative,
38
+ # but this method should only return true if it is.
39
+ # @param base [String] The base filename. If `uri` is relative,
40
+ # it should be interpreted as relative to `base`.
41
+ # `base` is guaranteed to be in a format importable by this importer.
42
+ # @param options [{Symbol => Object}] Options for the Sass file
43
+ # containing the `@import` that's currently being resolved.
44
+ # @return [Sass::Engine, nil] An Engine containing the imported file,
45
+ # or nil if it couldn't be found or was in the wrong format.
46
+ def find_relative(uri, base, options)
47
+ Sass::Util.abstract(self)
48
+ end
49
+
50
+ # Find a Sass file, if it exists.
51
+ #
52
+ # This is the primary entry point of the Importer.
53
+ # It corresponds directly to an `@import` statement in Sass.
54
+ # It should do three basic things:
55
+ #
56
+ # * Determine if the URI is in this importer's format.
57
+ # If not, return nil.
58
+ # * Determine if the file indicated by the URI actually exists and is readable.
59
+ # If not, return nil.
60
+ # * Read the file and place the contents in a {Sass::Engine}.
61
+ # Return that engine.
62
+ #
63
+ # If this importer's format allows for file extensions,
64
+ # it should treat them the same way as the default {Filesystem} importer.
65
+ # If the URI explicitly has a `.sass` or `.scss` filename,
66
+ # the importer should look for that exact file
67
+ # and import it as the syntax indicated.
68
+ # If it doesn't exist, the importer should return nil.
69
+ #
70
+ # If the URI doesn't have either of these extensions,
71
+ # the importer should look for files with the extensions.
72
+ # If no such files exist, it should return nil.
73
+ #
74
+ # The {Sass::Engine} to be returned should be passed `options`,
75
+ # with a few modifications. `:filename` and `:syntax` should be set appropriately,
76
+ # and `:importer` should be set to this importer.
77
+ #
78
+ # @param uri [String] The URI to import.
79
+ # @param options [{Symbol => Object}] Options for the Sass file
80
+ # containing the `@import` that's currently being resolved.
81
+ # This is safe for subclasses to modify destructively.
82
+ # Callers should only pass in a value they don't mind being destructively modified.
83
+ # @return [Sass::Engine, nil] An Engine containing the imported file,
84
+ # or nil if it couldn't be found or was in the wrong format.
85
+ def find(uri, options)
86
+ Sass::Util.abstract(self)
87
+ end
88
+
89
+ # Returns the time the given Sass file was last modified.
90
+ #
91
+ # If the given file has been deleted or the time can't be accessed
92
+ # for some other reason, this should return nil.
93
+ #
94
+ # @param uri [String] The URI of the file to check.
95
+ # Comes from a `:filename` option set on an engine returned by this importer.
96
+ # @param options [{Symbol => Objet}] Options for the Sass file
97
+ # containing the `@import` currently being checked.
98
+ # @return [Time, nil]
99
+ def mtime(uri, options)
100
+ Sass::Util.abstract(self)
101
+ end
102
+
103
+ # Get the cache key pair for the given Sass URI.
104
+ # The URI need not be checked for validity.
105
+ #
106
+ # The only strict requirement is that the returned pair of strings
107
+ # uniquely identify the file at the given URI.
108
+ # However, the first component generally corresponds roughly to the directory,
109
+ # and the second to the basename, of the URI.
110
+ #
111
+ # Note that keys must be unique *across importers*.
112
+ # Thus it's probably a good idea to include the importer name
113
+ # at the beginning of the first component.
114
+ #
115
+ # @param uri [String] A URI known to be valid for this importer.
116
+ # @param options [{Symbol => Object}] Options for the Sass file
117
+ # containing the `@import` currently being checked.
118
+ # @return [(String, String)] The key pair which uniquely identifies
119
+ # the file at the given URI.
120
+ def key(uri, options)
121
+ Sass::Util.abstract(self)
122
+ end
123
+
124
+ # A string representation of the importer.
125
+ # Should be overridden by subclasses.
126
+ #
127
+ # This is used to help debugging,
128
+ # and should usually just show the load path encapsulated by this importer.
129
+ #
130
+ # @return [String]
131
+ def to_s
132
+ Sass::Util.abstract(self)
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+
@@ -0,0 +1,121 @@
1
+ require 'pathname'
2
+
3
+ module Sass
4
+ module Importers
5
+ # The default importer, used for any strings found in the load path.
6
+ # Simply loads Sass files from the filesystem using the default logic.
7
+ class Filesystem < Base
8
+ # Creates a new filesystem importer that imports files relative to a given path.
9
+ #
10
+ # @param root [String] The root path.
11
+ # This importer will import files relative to this path.
12
+ def initialize(root)
13
+ @root = root
14
+ end
15
+
16
+ # @see Base#find_relative
17
+ def find_relative(name, base, options)
18
+ _find(File.dirname(base), name, options)
19
+ end
20
+
21
+ # @see Base#find
22
+ def find(name, options)
23
+ _find(@root, name, options)
24
+ end
25
+
26
+ # @see Base#mtime
27
+ def mtime(name, options)
28
+ file = find_real_file(@root, name)
29
+ File.mtime(name)
30
+ rescue Errno::ENOENT
31
+ nil
32
+ end
33
+
34
+ # @see Base#key
35
+ def key(name, options)
36
+ [self.class.name + ":" + File.dirname(File.expand_path(name)),
37
+ File.basename(name)]
38
+ end
39
+
40
+ # @see Base#to_s
41
+ def to_s
42
+ @root
43
+ end
44
+
45
+ protected
46
+
47
+ # A hash from file extensions to the syntaxes for those extensions.
48
+ # The syntaxes must be `:sass` or `:scss`.
49
+ #
50
+ # This can be overridden by subclasses that want normal filesystem importing
51
+ # with unusual extensions.
52
+ #
53
+ # @return [{String => Symbol}]
54
+ def extensions
55
+ {'sass' => :sass, 'scss' => :scss}
56
+ end
57
+
58
+ # Given an `@import`ed path, returns an array of possible
59
+ # on-disk filenames and their corresponding syntaxes for that path.
60
+ #
61
+ # @param name [String] The filename.
62
+ # @return [Array(String, Symbol)] An array of pairs.
63
+ # The first element of each pair is a filename to look for;
64
+ # the second element is the syntax that file would be in (`:sass` or `:scss`).
65
+ def possible_files(name)
66
+ dirname, basename, extname = split(name)
67
+ sorted_exts = extensions.sort
68
+ syntax = extensions[extname]
69
+
70
+ Sass::Util.flatten(
71
+ ["#{dirname}/#{basename}", "#{dirname}/_#{basename}"].map do |name|
72
+ next [["#{name}.#{extensions.invert[syntax]}", syntax]] if syntax
73
+ sorted_exts.map {|ext, syn| ["#{name}.#{ext}", syn]}
74
+ end, 1)
75
+ end
76
+
77
+ # Given a base directory and an `@import`ed name,
78
+ # finds an existant file that matches the name.
79
+ #
80
+ # @param dir [String] The directory relative to which to search.
81
+ # @param name [String] The filename to search for.
82
+ # @return [(String, Symbol)] A filename-syntax pair.
83
+ def find_real_file(dir, name)
84
+ possible_files(name).each do |f, s|
85
+ if File.exists?(full_path = join(dir, f))
86
+ return full_path, s
87
+ end
88
+ end
89
+ nil
90
+ end
91
+
92
+ # Splits a filename into three parts, a directory part, a basename, and an extension
93
+ # Only the known extensions returned from the extensions method will be recognized as such.
94
+ def split(name)
95
+ extension = nil
96
+ dirname, basename = File.dirname(name), File.basename(name)
97
+ if basename =~ /^(.*)\.(#{extensions.keys.map{|e| Regexp.escape(e)}.join('|')})$/
98
+ basename = $1
99
+ extension = $2
100
+ end
101
+ [dirname, basename, extension]
102
+ end
103
+
104
+ private
105
+
106
+ def _find(dir, name, options)
107
+ full_filename, syntax = find_real_file(dir, name)
108
+ return unless full_filename && File.readable?(full_filename)
109
+
110
+ options[:syntax] = syntax
111
+ options[:filename] = full_filename
112
+ options[:importer] = self
113
+ Sass::Engine.new(File.read(full_filename), options)
114
+ end
115
+
116
+ def join(base, path)
117
+ Pathname.new(base).join(path).to_s
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,363 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'less'
4
+
5
+ module Less
6
+ # This is the class that Treetop defines for parsing Less files.
7
+ # Since not everything gets parsed into the AST but is instead resolved at parse-time,
8
+ # we need to override some of it so that it can be converted into Sass.
9
+ module StyleSheet
10
+ # Selector mixins that don't have arguments.
11
+ # This depends only on the syntax at the call site;
12
+ # if it doesn't use parens, it hits this production,
13
+ # regardless of whether the mixin being called has arguments or not.
14
+ module Mixin4
15
+ def build_with_sass(env)
16
+ selectors.build(env, :mixin).each do |path|
17
+ el = path.inject(env.root) do |current, node|
18
+ current.descend(node.selector, node) or raise MixinNameError, "#{selectors.text_value} in #{env}"
19
+ end
20
+ if el.is_a?(Node::Mixin::Def)
21
+ # Calling a mixin with arguments, which gets compiled to a Sass mixin
22
+ env << Node::Mixin::Call.new(el, [], env)
23
+ else
24
+ # Calling a mixin without arguments, which gets compiled to @extend
25
+ sel = selector_str(path)
26
+ base = selector_str(selector_base(path))
27
+ if base == sel
28
+ env << Node::SassNode.new(Sass::Tree::ExtendNode.new([sel]))
29
+ else
30
+ Sass::Util.sass_warn <<WARNING
31
+ WARNING: Sass doesn't support mixing in selector sequences.
32
+ Replacing "#{sel}" with "@extend #{base}"
33
+ WARNING
34
+ env << Node::SassNode.new(Sass::Tree::CommentNode.new("// #{sel};", true))
35
+ env << Node::SassNode.new(Sass::Tree::ExtendNode.new([base]))
36
+ end
37
+ end
38
+ end
39
+ end
40
+ alias_method :build_without_sass, :build
41
+ alias_method :build, :build_with_sass
42
+
43
+ def selector_base(path)
44
+ el, i = Sass::Util.enum_with_index(path).to_a.reverse.find {|e, i| e.selector !~ /^:{1,2}$/} ||
45
+ [path.first, 0]
46
+ sel = (el.selector =~ /^:{0,2}$/ ? el.selector : "")
47
+ [Node::Element.new(el.name, sel)] + path[i+1..-1]
48
+ end
49
+
50
+ def selector_str(path)
51
+ path.map {|e| e.sass_selector_str}.join(' ').gsub(' :', ':')
52
+ end
53
+ end
54
+
55
+ # Property and variable declarations.
56
+ # We want to keep track of the line number
57
+ # so we don't space out the variables too much in the generated Sass.
58
+ module Declaration3
59
+ def build_with_sass(env)
60
+ build_without_sass(env)
61
+ env.rules.last.src_line = input.line_of(interval.first)
62
+ end
63
+ alias_method :build_without_sass, :build
64
+ alias_method :build, :build_with_sass
65
+ end
66
+
67
+ # Comma-separated selectors.
68
+ # Less breaks these into completely separate nodes.
69
+ # Since we don't want this duplication in the Sass,
70
+ # we modify the production to keep track of the original group
71
+ # so we can reconstruct it later on.
72
+ module Selectors2
73
+ def build_with_sass(env, method)
74
+ arr = build_without_sass(env, method)
75
+ return arr if method == :mixin
76
+ rarr = arr.map {|e| e.top(env)}
77
+ rarr.each {|e| e.group = rarr}
78
+ arr
79
+ end
80
+ alias_method :build_without_sass, :build
81
+ alias_method :build, :build_with_sass
82
+ end
83
+
84
+ # Attribute accessors.
85
+ # Sass just flat-out doesn't support these,
86
+ # so we print a warning to that effect and compile them to comments.
87
+ module Accessor1
88
+ def build(env)
89
+ Sass::Util.sass_warn <<WARNING
90
+ WARNING: Sass doesn't support attribute accessors.
91
+ Ignoring #{text_value}
92
+ WARNING
93
+ Node::Anonymous.new("/* #{text_value} */")
94
+ end
95
+ end
96
+
97
+ # @import statements.
98
+ # Less handles these during parse-time,
99
+ # so we want to wrap them up as a node in the tree.
100
+ # We also include the nodes, though,
101
+ # since we want to have access to the mixins
102
+ # so we can tell if they take arguments or not.
103
+ # The included nodes are hidden so they don't appear in the output.
104
+ module Import1
105
+ def build_with_sass(env)
106
+ line = input.line_of(interval.first)
107
+ import = Sass::Tree::ImportNode.new(url.value.gsub(/\.less$/, ''))
108
+ import.line = input.line_of(interval.first)
109
+ env << Node::SassNode.new(import)
110
+ old_rules = env.rules.dup
111
+ build_without_sass env
112
+ (env.rules - old_rules).each {|r| r.hide_in_sass = true}
113
+ rescue ImportError => e
114
+ raise Sass::SyntaxError.new("File to import #{url.text_value} not found or unreadable", :line => line)
115
+ end
116
+ alias_method :build_without_sass, :build
117
+ alias_method :build, :build_with_sass
118
+ end
119
+
120
+ # The IE-specific `alpha(opacity=@var)`.
121
+ # Less manually resolves the variable here at parse-time.
122
+ # We want to keep the variable around,
123
+ # so we compile this to a function.
124
+ # Less doesn't actually have an `=` operator,
125
+ # but that's okay since it's just getting compiled to Sass anyway.
126
+ module Entity::Alpha1
127
+ def build(env)
128
+ Node::Function.new("alpha",
129
+ [Node::Expression.new([
130
+ Node::Keyword.new("opacity"),
131
+ Node::Operator.new("="),
132
+ variable.build])])
133
+ end
134
+ end
135
+ end
136
+
137
+ # The Less AST classes for the document,
138
+ # including both stylesheet-level nodes and expression-level nodes.
139
+ # The main purpose of overriding these is to add `#to_sass_tree` functions
140
+ # for converting to Sass.
141
+ module Node
142
+ module Entity
143
+ attr_accessor :hide_in_sass
144
+ attr_accessor :src_line
145
+ end
146
+
147
+ class Element
148
+ attr_accessor :group
149
+
150
+ def top(env)
151
+ return self if parent.equal?(env)
152
+ return parent.top(env)
153
+ end
154
+
155
+ def to_sass_tree
156
+ if root?
157
+ root = Sass::Tree::RootNode.new("")
158
+ rules.each {|r| root << r.to_sass_tree}
159
+ return root
160
+ end
161
+ return if hide_in_sass
162
+ return if !self.equal?(group.first)
163
+
164
+ last_el = nil
165
+ sel = group.map do |el|
166
+ comma_sel = []
167
+ loop do
168
+ comma_sel << el.sass_selector_str
169
+ break unless el.rules.size == 1 && el.rules.first.is_a?(Element)
170
+ el = el.rules.first
171
+ end
172
+ last_el = el
173
+ comma_sel = comma_sel.join(' ').gsub(' :', ':')
174
+ comma_sel.gsub!(/^:/, '&:') unless parent.root?
175
+ comma_sel
176
+ end.join(', ')
177
+
178
+ rule = Sass::Tree::RuleNode.new([sel])
179
+ last_el.rules.each {|r| rule << r.to_sass_tree}
180
+ return rule
181
+ end
182
+
183
+ def sass_selector_str
184
+ case @selector
185
+ when /[+>~]/; "#{@selector} #{@name}"
186
+ else @selector + @name
187
+ end
188
+ end
189
+ end
190
+
191
+ module Mixin
192
+ class Call
193
+ def to_sass_tree
194
+ return if hide_in_sass
195
+ Sass::Tree::MixinNode.new(@mixin.name.gsub(/^\./, ''), @params.map {|v| v.to_sass_tree})
196
+ end
197
+ end
198
+
199
+ class Def
200
+ def to_sass_tree
201
+ return if hide_in_sass
202
+ mixin = Sass::Tree::MixinDefNode.new(name, @params.map do |v|
203
+ v.value.flatten!
204
+ [Sass::Script::Variable.new(v), v.value.to_sass_tree]
205
+ end)
206
+ rules.each {|r| mixin << r.to_sass_tree}
207
+ mixin
208
+ end
209
+ end
210
+ end
211
+
212
+ class SassNode
213
+ include Entity
214
+
215
+ def initialize(node)
216
+ @node = node
217
+ end
218
+
219
+ def to_sass_tree
220
+ return if hide_in_sass
221
+ @node
222
+ end
223
+ end
224
+
225
+ class Property
226
+ def to_sass_tree
227
+ return if hide_in_sass
228
+ Sass::Tree::PropNode.new([self], @value.to_sass_tree, :new)
229
+ end
230
+ end
231
+
232
+ class Expression
233
+ def to_sass_tree
234
+ if first.is_a?(Array)
235
+ val = map {|e| _to_sass_tree(e)}.inject(nil) do |e, i|
236
+ next i unless e
237
+ Sass::Script::Operation.new(e, i, :comma)
238
+ end
239
+ else
240
+ val = _to_sass_tree(self)
241
+ end
242
+ val.options = {}
243
+ val
244
+ end
245
+
246
+ private
247
+
248
+ LESS_TO_SASS_OPERATORS = {"-" => :minus, "+" => :plus, "*" => :times, "/" => :div, "=" => :single_eq}
249
+ def _to_sass_tree(arr)
250
+ return Sass::Script::UnaryOperation.new(_to_sass_tree(arr[1..-1]), :minus) if arr[0] == "-"
251
+ _to_sass_tree2(*_sass_split(arr))
252
+ end
253
+
254
+ def _to_sass_tree2(first, rest)
255
+ return first if rest.empty?
256
+ if rest[0].is_a?(Operator)
257
+ op = LESS_TO_SASS_OPERATORS[rest[0]]
258
+ if op == :times || op == :div
259
+ second, rest = _sass_split(rest[1..-1])
260
+ return _to_sass_tree2(Sass::Script::Operation.new(first, second, op), rest)
261
+ else
262
+ return Sass::Script::Operation.new(first, _to_sass_tree(rest[1..-1]), op)
263
+ end
264
+ end
265
+
266
+ Sass::Script::Operation.new(first, _to_sass_tree(rest), :concat)
267
+ end
268
+
269
+ def _sass_split(arr)
270
+ return arr[0].to_sass_tree, arr[1..-1] unless arr[0] == "("
271
+ parens = 1
272
+ i = arr[1..-1].each_with_index do |e, i|
273
+ parens += 1 if e == "("
274
+ parens -= 1 if e == ")"
275
+ break i if parens == 0
276
+ end
277
+
278
+ return _to_sass_tree(arr[1...i+1]), arr[i+2..-1]
279
+ end
280
+ end
281
+
282
+ class Color
283
+ def to_sass_tree
284
+ Sass::Script::Color.new(:red => r, :green => g, :blue => b, :alpha => a)
285
+ end
286
+ end
287
+
288
+ class Number
289
+ def to_sass_tree
290
+ Sass::Script::Number.new(self, [self.unit])
291
+ end
292
+ end
293
+
294
+ class Variable
295
+ def to_sass_tree
296
+ if @declaration
297
+ return if hide_in_sass
298
+ node = Sass::Tree::VariableNode.new(self, @value.to_sass_tree, false)
299
+ node.line = self.src_line
300
+ node
301
+ else
302
+ Sass::Script::Variable.new(self)
303
+ end
304
+ end
305
+ end
306
+
307
+ class Function
308
+ def to_sass_tree
309
+ Sass::Script::Funcall.new(self, @args.map {|a| a.to_sass_tree})
310
+ end
311
+ end
312
+
313
+ class Keyword
314
+ def to_sass_tree
315
+ Sass::Script::String.new(self)
316
+ end
317
+ end
318
+
319
+ class Anonymous
320
+ def to_sass_tree
321
+ Sass::Script::String.new(self)
322
+ end
323
+ end
324
+
325
+ class Quoted
326
+ def to_sass_tree
327
+ Sass::Script::String.new(self, true)
328
+ end
329
+ end
330
+
331
+ class FontFamily
332
+ def to_sass_tree
333
+ @family.map {|f| f.to_sass_tree}.inject(nil) do |e, f|
334
+ next f unless e
335
+ Sass::Script::Operation.new(e, f, :comma)
336
+ end
337
+ end
338
+ end
339
+ end
340
+
341
+ # The entry point to Less.
342
+ # By default Less doesn't preserve the filename of the file being parsed,
343
+ # which is unpleasant for error reporting.
344
+ # Our monkeypatch keeps it around.
345
+ class Engine
346
+ def initialize_with_sass(obj, opts = {})
347
+ initialize_without_sass(obj, opts)
348
+ @filename = obj.path if obj.is_a?(File)
349
+ end
350
+ alias_method :initialize_without_sass, :initialize
351
+ alias_method :initialize, :initialize_with_sass
352
+
353
+ def parse_with_sass
354
+ parse_without_sass
355
+ rescue Sass::SyntaxError => e
356
+ e.modify_backtrace(:filename => @filename)
357
+ raise e
358
+ end
359
+ alias_method :parse_without_sass, :parse
360
+ alias_method :parse, :parse_with_sass
361
+ alias_method :to_tree, :parse
362
+ end
363
+ end