sass 3.1.0 → 3.3.0

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 (260) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING +1 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +29 -17
  5. data/Rakefile +43 -9
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -0
  8. data/VERSION_NAME +1 -1
  9. data/bin/sass +6 -1
  10. data/bin/sass-convert +6 -1
  11. data/bin/scss +6 -1
  12. data/ext/mkrf_conf.rb +27 -0
  13. data/lib/sass/cache_stores/base.rb +7 -3
  14. data/lib/sass/cache_stores/chain.rb +3 -2
  15. data/lib/sass/cache_stores/filesystem.rb +5 -7
  16. data/lib/sass/cache_stores/memory.rb +1 -1
  17. data/lib/sass/cache_stores/null.rb +2 -2
  18. data/lib/sass/callbacks.rb +2 -1
  19. data/lib/sass/css.rb +168 -53
  20. data/lib/sass/engine.rb +502 -174
  21. data/lib/sass/environment.rb +151 -111
  22. data/lib/sass/error.rb +7 -7
  23. data/lib/sass/exec.rb +176 -60
  24. data/lib/sass/features.rb +40 -0
  25. data/lib/sass/importers/base.rb +46 -7
  26. data/lib/sass/importers/deprecated_path.rb +51 -0
  27. data/lib/sass/importers/filesystem.rb +113 -30
  28. data/lib/sass/importers.rb +1 -0
  29. data/lib/sass/logger/base.rb +30 -0
  30. data/lib/sass/logger/log_level.rb +45 -0
  31. data/lib/sass/logger.rb +12 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin/compiler.rb +194 -104
  34. data/lib/sass/plugin/configuration.rb +18 -25
  35. data/lib/sass/plugin/merb.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +37 -11
  37. data/lib/sass/plugin.rb +10 -13
  38. data/lib/sass/railtie.rb +2 -1
  39. data/lib/sass/repl.rb +5 -6
  40. data/lib/sass/script/css_lexer.rb +8 -4
  41. data/lib/sass/script/css_parser.rb +5 -2
  42. data/lib/sass/script/functions.rb +1547 -618
  43. data/lib/sass/script/lexer.rb +122 -72
  44. data/lib/sass/script/parser.rb +304 -135
  45. data/lib/sass/script/tree/funcall.rb +306 -0
  46. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
  47. data/lib/sass/script/tree/list_literal.rb +77 -0
  48. data/lib/sass/script/tree/literal.rb +45 -0
  49. data/lib/sass/script/tree/map_literal.rb +64 -0
  50. data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
  51. data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
  52. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
  53. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
  54. data/lib/sass/script/tree/variable.rb +57 -0
  55. data/lib/sass/script/tree.rb +15 -0
  56. data/lib/sass/script/value/arg_list.rb +36 -0
  57. data/lib/sass/script/value/base.rb +238 -0
  58. data/lib/sass/script/value/bool.rb +40 -0
  59. data/lib/sass/script/{color.rb → value/color.rb} +256 -74
  60. data/lib/sass/script/value/deprecated_false.rb +55 -0
  61. data/lib/sass/script/value/helpers.rb +155 -0
  62. data/lib/sass/script/value/list.rb +128 -0
  63. data/lib/sass/script/value/map.rb +70 -0
  64. data/lib/sass/script/value/null.rb +49 -0
  65. data/lib/sass/script/{number.rb → value/number.rb} +115 -62
  66. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  67. data/lib/sass/script/value.rb +12 -0
  68. data/lib/sass/script.rb +35 -9
  69. data/lib/sass/scss/css_parser.rb +2 -12
  70. data/lib/sass/scss/parser.rb +657 -230
  71. data/lib/sass/scss/rx.rb +17 -12
  72. data/lib/sass/scss/static_parser.rb +37 -6
  73. data/lib/sass/scss.rb +0 -1
  74. data/lib/sass/selector/abstract_sequence.rb +35 -3
  75. data/lib/sass/selector/comma_sequence.rb +29 -14
  76. data/lib/sass/selector/sequence.rb +371 -74
  77. data/lib/sass/selector/simple.rb +28 -13
  78. data/lib/sass/selector/simple_sequence.rb +163 -36
  79. data/lib/sass/selector.rb +138 -36
  80. data/lib/sass/shared.rb +3 -5
  81. data/lib/sass/source/map.rb +196 -0
  82. data/lib/sass/source/position.rb +39 -0
  83. data/lib/sass/source/range.rb +41 -0
  84. data/lib/sass/stack.rb +126 -0
  85. data/lib/sass/supports.rb +228 -0
  86. data/lib/sass/tree/at_root_node.rb +82 -0
  87. data/lib/sass/tree/comment_node.rb +34 -29
  88. data/lib/sass/tree/content_node.rb +9 -0
  89. data/lib/sass/tree/css_import_node.rb +60 -0
  90. data/lib/sass/tree/debug_node.rb +3 -3
  91. data/lib/sass/tree/directive_node.rb +33 -3
  92. data/lib/sass/tree/each_node.rb +9 -9
  93. data/lib/sass/tree/extend_node.rb +20 -6
  94. data/lib/sass/tree/for_node.rb +6 -6
  95. data/lib/sass/tree/function_node.rb +12 -4
  96. data/lib/sass/tree/if_node.rb +2 -15
  97. data/lib/sass/tree/import_node.rb +11 -5
  98. data/lib/sass/tree/media_node.rb +27 -11
  99. data/lib/sass/tree/mixin_def_node.rb +15 -4
  100. data/lib/sass/tree/mixin_node.rb +27 -7
  101. data/lib/sass/tree/node.rb +69 -35
  102. data/lib/sass/tree/prop_node.rb +47 -31
  103. data/lib/sass/tree/return_node.rb +4 -3
  104. data/lib/sass/tree/root_node.rb +20 -4
  105. data/lib/sass/tree/rule_node.rb +37 -26
  106. data/lib/sass/tree/supports_node.rb +38 -0
  107. data/lib/sass/tree/trace_node.rb +33 -0
  108. data/lib/sass/tree/variable_node.rb +10 -4
  109. data/lib/sass/tree/visitors/base.rb +5 -8
  110. data/lib/sass/tree/visitors/check_nesting.rb +67 -52
  111. data/lib/sass/tree/visitors/convert.rb +134 -53
  112. data/lib/sass/tree/visitors/cssize.rb +245 -51
  113. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  114. data/lib/sass/tree/visitors/extend.rb +68 -0
  115. data/lib/sass/tree/visitors/perform.rb +331 -105
  116. data/lib/sass/tree/visitors/set_options.rb +125 -0
  117. data/lib/sass/tree/visitors/to_css.rb +259 -95
  118. data/lib/sass/tree/warn_node.rb +3 -3
  119. data/lib/sass/tree/while_node.rb +3 -3
  120. data/lib/sass/util/cross_platform_random.rb +19 -0
  121. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  122. data/lib/sass/util/normalized_map.rb +130 -0
  123. data/lib/sass/util/ordered_hash.rb +192 -0
  124. data/lib/sass/util/subset_map.rb +11 -2
  125. data/lib/sass/util/test.rb +9 -0
  126. data/lib/sass/util.rb +565 -39
  127. data/lib/sass/version.rb +27 -15
  128. data/lib/sass.rb +39 -4
  129. data/test/sass/cache_test.rb +15 -0
  130. data/test/sass/compiler_test.rb +223 -0
  131. data/test/sass/conversion_test.rb +901 -107
  132. data/test/sass/css2sass_test.rb +94 -0
  133. data/test/sass/engine_test.rb +1059 -164
  134. data/test/sass/exec_test.rb +86 -0
  135. data/test/sass/extend_test.rb +933 -837
  136. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  137. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  138. data/test/sass/functions_test.rb +995 -136
  139. data/test/sass/importer_test.rb +338 -18
  140. data/test/sass/logger_test.rb +58 -0
  141. data/test/sass/more_results/more_import.css +2 -2
  142. data/test/sass/plugin_test.rb +114 -30
  143. data/test/sass/results/cached_import_option.css +3 -0
  144. data/test/sass/results/filename_fn.css +3 -0
  145. data/test/sass/results/import.css +2 -2
  146. data/test/sass/results/import_charset.css +1 -0
  147. data/test/sass/results/import_charset_1_8.css +1 -0
  148. data/test/sass/results/import_charset_ibm866.css +1 -0
  149. data/test/sass/results/import_content.css +1 -0
  150. data/test/sass/results/script.css +1 -1
  151. data/test/sass/results/scss_import.css +2 -2
  152. data/test/sass/results/units.css +2 -2
  153. data/test/sass/script_conversion_test.rb +43 -1
  154. data/test/sass/script_test.rb +380 -36
  155. data/test/sass/scss/css_test.rb +257 -75
  156. data/test/sass/scss/scss_test.rb +2322 -110
  157. data/test/sass/source_map_test.rb +887 -0
  158. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  159. data/test/sass/templates/_double_import_loop2.sass +1 -0
  160. data/test/sass/templates/_filename_fn_import.scss +11 -0
  161. data/test/sass/templates/_imported_content.sass +3 -0
  162. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  163. data/test/sass/templates/bork5.sass +3 -0
  164. data/test/sass/templates/cached_import_option.scss +3 -0
  165. data/test/sass/templates/double_import_loop1.sass +1 -0
  166. data/test/sass/templates/filename_fn.scss +18 -0
  167. data/test/sass/templates/import_charset.sass +2 -0
  168. data/test/sass/templates/import_charset_1_8.sass +2 -0
  169. data/test/sass/templates/import_charset_ibm866.sass +2 -0
  170. data/test/sass/templates/import_content.sass +4 -0
  171. data/test/sass/templates/same_name_different_ext.sass +2 -0
  172. data/test/sass/templates/same_name_different_ext.scss +1 -0
  173. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  174. data/test/sass/templates/single_import_loop.sass +1 -0
  175. data/test/sass/templates/subdir/import_up1.scss +1 -0
  176. data/test/sass/templates/subdir/import_up2.scss +1 -0
  177. data/test/sass/test_helper.rb +1 -1
  178. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  179. data/test/sass/util/normalized_map_test.rb +51 -0
  180. data/test/sass/util_test.rb +183 -0
  181. data/test/sass/value_helpers_test.rb +181 -0
  182. data/test/test_helper.rb +45 -5
  183. data/vendor/listen/CHANGELOG.md +228 -0
  184. data/vendor/listen/CONTRIBUTING.md +38 -0
  185. data/vendor/listen/Gemfile +30 -0
  186. data/vendor/listen/Guardfile +8 -0
  187. data/vendor/{fssm → listen}/LICENSE +1 -1
  188. data/vendor/listen/README.md +315 -0
  189. data/vendor/listen/Rakefile +47 -0
  190. data/vendor/listen/Vagrantfile +96 -0
  191. data/vendor/listen/lib/listen/adapter.rb +214 -0
  192. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  193. data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
  194. data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
  195. data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
  196. data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
  197. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  198. data/vendor/listen/lib/listen/directory_record.rb +371 -0
  199. data/vendor/listen/lib/listen/listener.rb +225 -0
  200. data/vendor/listen/lib/listen/multi_listener.rb +143 -0
  201. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  202. data/vendor/listen/lib/listen/version.rb +3 -0
  203. data/vendor/listen/lib/listen.rb +40 -0
  204. data/vendor/listen/listen.gemspec +22 -0
  205. data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
  206. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  207. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  208. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  209. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  210. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  211. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  212. data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
  213. data/vendor/listen/spec/listen/listener_spec.rb +169 -0
  214. data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
  215. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  216. data/vendor/listen/spec/listen_spec.rb +73 -0
  217. data/vendor/listen/spec/spec_helper.rb +21 -0
  218. data/vendor/listen/spec/support/adapter_helper.rb +629 -0
  219. data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
  220. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  221. data/vendor/listen/spec/support/listeners_helper.rb +156 -0
  222. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  223. metadata +344 -271
  224. data/lib/sass/less.rb +0 -382
  225. data/lib/sass/script/bool.rb +0 -18
  226. data/lib/sass/script/funcall.rb +0 -162
  227. data/lib/sass/script/list.rb +0 -76
  228. data/lib/sass/script/literal.rb +0 -245
  229. data/lib/sass/script/variable.rb +0 -54
  230. data/lib/sass/scss/sass_parser.rb +0 -11
  231. data/test/sass/less_conversion_test.rb +0 -653
  232. data/vendor/fssm/README.markdown +0 -55
  233. data/vendor/fssm/Rakefile +0 -59
  234. data/vendor/fssm/VERSION.yml +0 -5
  235. data/vendor/fssm/example.rb +0 -9
  236. data/vendor/fssm/fssm.gemspec +0 -77
  237. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  238. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  239. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  240. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  241. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  242. data/vendor/fssm/lib/fssm/path.rb +0 -91
  243. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  244. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  245. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  246. data/vendor/fssm/lib/fssm/support.rb +0 -63
  247. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  248. data/vendor/fssm/lib/fssm.rb +0 -33
  249. data/vendor/fssm/profile/prof-cache.rb +0 -40
  250. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  251. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  252. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  253. data/vendor/fssm/profile/prof.html +0 -2379
  254. data/vendor/fssm/spec/path_spec.rb +0 -75
  255. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  256. data/vendor/fssm/spec/root/file.css +0 -0
  257. data/vendor/fssm/spec/root/file.rb +0 -0
  258. data/vendor/fssm/spec/root/file.yml +0 -0
  259. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  260. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -0,0 +1,169 @@
1
+ require 'spec_helper'
2
+
3
+ describe Listen::Listener do
4
+ let(:adapter) { mock(Listen::Adapter, :start => true).as_null_object }
5
+ let(:watched_directory) { File.dirname(__FILE__) }
6
+
7
+ subject { described_class.new(watched_directory) }
8
+
9
+ before do
10
+ Listen::Adapter.stub(:select_and_initialize) { adapter }
11
+ # Don't build a record of the files inside the base directory.
12
+ subject.directory_record.stub(:build)
13
+ end
14
+
15
+ it_should_behave_like 'a listener to changes on a file-system'
16
+
17
+ describe '#initialize' do
18
+ context 'with no options' do
19
+ it 'sets the directory' do
20
+ subject.directory.should eq watched_directory
21
+ end
22
+
23
+ it 'converts the passed path into an absolute path - #21' do
24
+ described_class.new(File.join(watched_directory, '..')).directory.should eq File.expand_path('..', watched_directory)
25
+ end
26
+
27
+ it 'sets the option for using relative paths in the callback to the default one' do
28
+ subject.instance_variable_get(:@use_relative_paths).should eq described_class::DEFAULT_TO_RELATIVE_PATHS
29
+ end
30
+ end
31
+
32
+ context 'with custom options' do
33
+ subject { described_class.new(watched_directory, :ignore => /\.ssh/, :filter => [/.*\.rb/,/.*\.md/],
34
+ :latency => 0.5, :force_polling => true, :relative_paths => true) }
35
+
36
+ it 'passes the custom ignored paths to the directory record' do
37
+ subject.directory_record.ignoring_patterns.should include /\.ssh/
38
+ end
39
+
40
+ it 'passes the custom filters to the directory record' do
41
+ subject.directory_record.filtering_patterns.should =~ [/.*\.rb/,/.*\.md/]
42
+ end
43
+
44
+ it 'sets the cutom option for using relative paths in the callback' do
45
+ subject.instance_variable_get(:@use_relative_paths).should be_true
46
+ end
47
+
48
+ it 'sets adapter_options' do
49
+ subject.instance_variable_get(:@adapter_options).should eq(:latency => 0.5, :force_polling => true)
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '#start' do
55
+ it 'selects and initializes an adapter' do
56
+ Listen::Adapter.should_receive(:select_and_initialize).with(watched_directory, {}) { adapter }
57
+ subject.start
58
+ end
59
+
60
+ it 'builds the directory record' do
61
+ subject.directory_record.should_receive(:build)
62
+ subject.start
63
+ end
64
+ end
65
+
66
+ context 'with a started listener' do
67
+ before do
68
+ subject.stub(:initialize_adapter) { adapter }
69
+ subject.start
70
+ end
71
+
72
+ describe '#unpause' do
73
+ it 'rebuilds the directory record' do
74
+ subject.directory_record.should_receive(:build)
75
+ subject.unpause
76
+ end
77
+ end
78
+ end
79
+
80
+ describe '#ignore'do
81
+ it 'delegates the work to the directory record' do
82
+ subject.directory_record.should_receive(:ignore).with 'some_directory'
83
+ subject.ignore 'some_directory'
84
+ end
85
+ end
86
+
87
+ describe '#ignore!'do
88
+ it 'delegates the work to the directory record' do
89
+ subject.directory_record.should_receive(:ignore!).with 'some_directory'
90
+ subject.ignore! 'some_directory'
91
+ end
92
+ end
93
+
94
+ describe '#filter' do
95
+ it 'delegates the work to the directory record' do
96
+ subject.directory_record.should_receive(:filter).with /\.txt$/
97
+ subject.filter /\.txt$/
98
+ end
99
+ end
100
+
101
+ describe '#filter!' do
102
+ it 'delegates the work to the directory record' do
103
+ subject.directory_record.should_receive(:filter!).with /\.txt$/
104
+ subject.filter! /\.txt$/
105
+ end
106
+ end
107
+
108
+
109
+ describe '#on_change' do
110
+ let(:directories) { %w{dir1 dir2 dir3} }
111
+ let(:changes) { {:modified => [], :added => [], :removed => []} }
112
+ let(:callback) { Proc.new { @called = true } }
113
+
114
+ before do
115
+ @called = false
116
+ subject.directory_record.stub(:fetch_changes => changes)
117
+ end
118
+
119
+ it 'fetches the changes of the directory record' do
120
+ subject.directory_record.should_receive(:fetch_changes).with(
121
+ directories, hash_including(:relative_paths => described_class::DEFAULT_TO_RELATIVE_PATHS)
122
+ )
123
+ subject.on_change(directories)
124
+ end
125
+
126
+ context 'with relative paths option set to true' do
127
+ subject { described_class.new(watched_directory, :relative_paths => true) }
128
+
129
+ it 'fetches the changes of the directory record' do
130
+ subject.directory_record.should_receive(:fetch_changes).with(directories, hash_including(:relative_paths => true))
131
+ subject.on_change(directories)
132
+ end
133
+ end
134
+
135
+ context 'with no changes to report' do
136
+ if RUBY_VERSION[/^1.8/]
137
+ it 'does not run the callback' do
138
+ subject.change(&callback)
139
+ subject.on_change(directories)
140
+ @called.should be_false
141
+ end
142
+ else
143
+ it 'does not run the callback' do
144
+ callback.should_not_receive(:call)
145
+ subject.change(&callback)
146
+ subject.on_change(directories)
147
+ end
148
+ end
149
+ end
150
+
151
+ context 'with changes to report' do
152
+ let(:changes) { {:modified => %w{path1}, :added => [], :removed => %w{path2}} }
153
+
154
+ if RUBY_VERSION[/^1.8/]
155
+ it 'runs the callback passing it the changes' do
156
+ subject.change(&callback)
157
+ subject.on_change(directories)
158
+ @called.should be_true
159
+ end
160
+ else
161
+ it 'runs the callback passing it the changes' do
162
+ callback.should_receive(:call).with(changes[:modified], changes[:added], changes[:removed])
163
+ subject.change(&callback)
164
+ subject.on_change(directories)
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,174 @@
1
+ require 'spec_helper'
2
+
3
+ describe Listen::MultiListener do
4
+ let(:adapter) { mock(Listen::Adapter, :start => true).as_null_object }
5
+ let(:watched_directories) { [File.dirname(__FILE__), File.expand_path('../..', __FILE__)] }
6
+
7
+ subject { described_class.new(*watched_directories) }
8
+
9
+ before do
10
+ Listen::Adapter.stub(:select_and_initialize) { adapter }
11
+ # Don't build a record of the files inside the base directory.
12
+ Listen::DirectoryRecord.any_instance.stub(:build)
13
+ end
14
+
15
+ it_should_behave_like 'a listener to changes on a file-system'
16
+
17
+ describe '#initialize' do
18
+ context 'with no options' do
19
+ it 'sets the directories' do
20
+ subject.directories.should =~ watched_directories
21
+ end
22
+
23
+ it 'converts the passed paths into absolute paths - #21' do
24
+ paths = watched_directories.map { |d| File.join(d, '..') }
25
+ described_class.new(*paths).directories.should =~ watched_directories.map{ |d| File.expand_path('..', d) }
26
+ end
27
+ end
28
+
29
+ context 'with custom options' do
30
+ subject do
31
+ args = watched_directories << {:ignore => /\.ssh/, :filter => [/.*\.rb/,/.*\.md/], :latency => 0.5, :force_polling => true}
32
+ described_class.new(*args)
33
+ end
34
+
35
+ it 'passes the custom ignored paths to each directory record' do
36
+ subject.directories_records.each do |r|
37
+ r.ignoring_patterns.should include /\.ssh/
38
+ end
39
+ end
40
+
41
+ it 'passes the custom filters to each directory record' do
42
+ subject.directories_records.each do |r|
43
+ r.filtering_patterns.should =~ [/.*\.rb/,/.*\.md/]
44
+ end
45
+ end
46
+
47
+ it 'sets adapter_options' do
48
+ subject.instance_variable_get(:@adapter_options).should eq(:latency => 0.5, :force_polling => true)
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#start' do
54
+ it 'selects and initializes an adapter' do
55
+ Listen::Adapter.should_receive(:select_and_initialize).with(watched_directories, {}) { adapter }
56
+ subject.start
57
+ end
58
+
59
+ it 'builds all directories records' do
60
+ subject.directories_records.each do |r|
61
+ r.should_receive(:build)
62
+ end
63
+ subject.start
64
+ end
65
+ end
66
+
67
+ context 'with a started listener' do
68
+ before do
69
+ subject.stub(:initialize_adapter) { adapter }
70
+ subject.start
71
+ end
72
+
73
+ describe '#unpause' do
74
+ it 'rebuilds all directories records' do
75
+ subject.directories_records.each do |r|
76
+ r.should_receive(:build)
77
+ end
78
+ subject.unpause
79
+ end
80
+ end
81
+ end
82
+
83
+ describe '#ignore' do
84
+ it 'delegates the work to each directory record' do
85
+ subject.directories_records.each do |r|
86
+ r.should_receive(:ignore).with 'some_directory'
87
+ end
88
+ subject.ignore 'some_directory'
89
+ end
90
+ end
91
+
92
+ describe '#ignore!' do
93
+ it 'delegates the work to each directory record' do
94
+ subject.directories_records.each do |r|
95
+ r.should_receive(:ignore!).with 'some_directory'
96
+ end
97
+ subject.ignore! 'some_directory'
98
+ end
99
+ end
100
+
101
+ describe '#filter' do
102
+ it 'delegates the work to each directory record' do
103
+ subject.directories_records.each do |r|
104
+ r.should_receive(:filter).with /\.txt$/
105
+ end
106
+ subject.filter /\.txt$/
107
+ end
108
+ end
109
+
110
+ describe '#filter!' do
111
+ it 'delegates the work to each directory record' do
112
+ subject.directories_records.each do |r|
113
+ r.should_receive(:filter!).with /\.txt$/
114
+ end
115
+ subject.filter! /\.txt$/
116
+ end
117
+ end
118
+
119
+ describe '#on_change' do
120
+ let(:directories) { %w{dir1 dir2 dir3} }
121
+ let(:changes) { {:modified => [], :added => [], :removed => []} }
122
+ let(:callback) { Proc.new { @called = true } }
123
+
124
+ before do
125
+ @called = false
126
+ subject.stub(:fetch_records_changes => changes)
127
+ end
128
+
129
+ it 'fetches the changes of all directories records' do
130
+ subject.unstub(:fetch_records_changes)
131
+
132
+ subject.directories_records.each do |record|
133
+ record.should_receive(:fetch_changes).with(
134
+ directories, hash_including(:relative_paths => described_class::DEFAULT_TO_RELATIVE_PATHS)
135
+ ).and_return(changes)
136
+ end
137
+ subject.on_change(directories)
138
+ end
139
+
140
+ context 'with no changes to report' do
141
+ if RUBY_VERSION[/^1.8/]
142
+ it 'does not run the callback' do
143
+ subject.change(&callback)
144
+ subject.on_change(directories)
145
+ @called.should be_false
146
+ end
147
+ else
148
+ it 'does not run the callback' do
149
+ callback.should_not_receive(:call)
150
+ subject.change(&callback)
151
+ subject.on_change(directories)
152
+ end
153
+ end
154
+ end
155
+
156
+ context 'with changes to report' do
157
+ let(:changes) { {:modified => %w{path1}, :added => [], :removed => %w{path2}} }
158
+
159
+ if RUBY_VERSION[/^1.8/]
160
+ it 'runs the callback passing it the changes' do
161
+ subject.change(&callback)
162
+ subject.on_change(directories)
163
+ @called.should be_true
164
+ end
165
+ else
166
+ it 'runs the callback passing it the changes' do
167
+ callback.should_receive(:call).with(changes[:modified], changes[:added], changes[:removed])
168
+ subject.change(&callback)
169
+ subject.on_change(directories)
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ def run_in_two_threads(proc1, proc2)
4
+ t1 = Thread.new &proc1
5
+ sleep test_latency # t1 must run before t2
6
+ t2 = Thread.new { proc2.call; Thread.kill t1 }
7
+ t2.join(test_latency * 2)
8
+ ensure
9
+ Thread.kill t1 if t1
10
+ Thread.kill t2 if t2
11
+ end
12
+
13
+ describe Listen::Turnstile do
14
+ before { @called = false }
15
+
16
+ describe '#wait' do
17
+ context 'without a signal' do
18
+ it 'blocks one thread indefinitely' do
19
+ run_in_two_threads lambda {
20
+ subject.wait
21
+ @called = true
22
+ }, lambda {
23
+ sleep test_latency
24
+ }
25
+ @called.should be_false
26
+ end
27
+ end
28
+
29
+ context 'with a signal' do
30
+ it 'blocks one thread until it recieves a signal from another thread' do
31
+ run_in_two_threads lambda {
32
+ subject.wait
33
+ @called = true
34
+ }, lambda {
35
+ subject.signal
36
+ sleep test_latency
37
+ }
38
+ @called.should be_true
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '#signal' do
44
+ context 'without a wait-call before' do
45
+ it 'does nothing' do
46
+ run_in_two_threads lambda {
47
+ subject.signal
48
+ @called = true
49
+ }, lambda {
50
+ sleep test_latency
51
+ }
52
+ @called.should be_true
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Listen do
4
+ describe '#to' do
5
+ context 'with one path to listen to' do
6
+ let(:listener) { mock(Listen::Listener) }
7
+ let(:listener_class) { Listen::Listener }
8
+
9
+ before { listener_class.stub(:new => listener) }
10
+
11
+ context 'without options' do
12
+ it 'creates an instance of Listner' do
13
+ listener_class.should_receive(:new).with('/path')
14
+ described_class.to('/path')
15
+ end
16
+ end
17
+
18
+ context 'with options' do
19
+ it 'creates an instance of Listner with the passed params' do
20
+ listener_class.should_receive(:new).with('/path', :filter => '**/*')
21
+ described_class.to('/path', :filter => '**/*')
22
+ end
23
+ end
24
+
25
+ context 'without a block' do
26
+ it 'returns the listener' do
27
+ described_class.to('/path', :filter => '**/*').should eq listener
28
+ end
29
+ end
30
+
31
+ context 'with a block' do
32
+ it 'starts the listner after creating it' do
33
+ listener.should_receive(:start)
34
+ described_class.to('/path', :filter => '**/*') { |modified, added, removed| }
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'with multiple paths to listen to' do
40
+ let(:multi_listener) { mock(Listen::MultiListener) }
41
+ let(:multi_listener_class) { Listen::MultiListener }
42
+
43
+ before { multi_listener_class.stub(:new => multi_listener) }
44
+
45
+ context 'without options' do
46
+ it 'creates an instance of MultiListner' do
47
+ multi_listener_class.should_receive(:new).with('path1', 'path2')
48
+ described_class.to('path1', 'path2')
49
+ end
50
+ end
51
+
52
+ context 'with options' do
53
+ it 'creates an instance of MultiListner with the passed params' do
54
+ multi_listener_class.should_receive(:new).with('path1', 'path2', :filter => '**/*')
55
+ described_class.to('path1', 'path2', :filter => '**/*')
56
+ end
57
+ end
58
+
59
+ context 'without a block' do
60
+ it 'returns a MultiListener instance created with the passed params' do
61
+ described_class.to('path1', 'path2', :filter => '**/*').should eq multi_listener
62
+ end
63
+ end
64
+
65
+ context 'with a block' do
66
+ it 'starts a MultiListener instance after creating it with the passed params' do
67
+ multi_listener.should_receive(:start)
68
+ described_class.to('path1', 'path2', :filter => '**/*') { |modified, added, removed| }
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,21 @@
1
+ require 'listen'
2
+
3
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
4
+
5
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
6
+ RSpec.configure do |config|
7
+ config.color_enabled = true
8
+ config.order = :random
9
+ config.filter_run :focus => true
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run_excluding :broken => true
13
+ config.fail_fast = true
14
+ end
15
+
16
+ def test_latency
17
+ 0.1
18
+ end
19
+
20
+ # Crash loud in tests!
21
+ Thread.abort_on_exception = true