sass 3.3.0 → 3.4.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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +58 -50
  4. data/Rakefile +1 -4
  5. data/VERSION +1 -1
  6. data/VERSION_DATE +1 -1
  7. data/VERSION_NAME +1 -1
  8. data/bin/sass +1 -1
  9. data/bin/scss +1 -1
  10. data/lib/sass/cache_stores/filesystem.rb +6 -2
  11. data/lib/sass/css.rb +1 -3
  12. data/lib/sass/engine.rb +37 -46
  13. data/lib/sass/environment.rb +13 -17
  14. data/lib/sass/error.rb +6 -9
  15. data/lib/sass/exec/base.rb +187 -0
  16. data/lib/sass/exec/sass_convert.rb +264 -0
  17. data/lib/sass/exec/sass_scss.rb +424 -0
  18. data/lib/sass/exec.rb +5 -771
  19. data/lib/sass/features.rb +7 -0
  20. data/lib/sass/importers/base.rb +7 -2
  21. data/lib/sass/importers/filesystem.rb +9 -25
  22. data/lib/sass/importers.rb +0 -1
  23. data/lib/sass/media.rb +1 -4
  24. data/lib/sass/plugin/compiler.rb +200 -83
  25. data/lib/sass/plugin/staleness_checker.rb +1 -1
  26. data/lib/sass/plugin.rb +3 -3
  27. data/lib/sass/script/css_lexer.rb +1 -1
  28. data/lib/sass/script/functions.rb +622 -268
  29. data/lib/sass/script/lexer.rb +99 -34
  30. data/lib/sass/script/parser.rb +24 -23
  31. data/lib/sass/script/tree/funcall.rb +1 -1
  32. data/lib/sass/script/tree/interpolation.rb +20 -2
  33. data/lib/sass/script/tree/selector.rb +26 -0
  34. data/lib/sass/script/tree/string_interpolation.rb +1 -1
  35. data/lib/sass/script/tree.rb +1 -0
  36. data/lib/sass/script/value/base.rb +7 -5
  37. data/lib/sass/script/value/bool.rb +0 -5
  38. data/lib/sass/script/value/color.rb +39 -21
  39. data/lib/sass/script/value/helpers.rb +107 -0
  40. data/lib/sass/script/value/list.rb +0 -15
  41. data/lib/sass/script/value/null.rb +0 -5
  42. data/lib/sass/script/value/number.rb +62 -14
  43. data/lib/sass/script/value/string.rb +59 -11
  44. data/lib/sass/script/value.rb +0 -1
  45. data/lib/sass/scss/css_parser.rb +8 -2
  46. data/lib/sass/scss/parser.rb +190 -328
  47. data/lib/sass/scss/rx.rb +15 -6
  48. data/lib/sass/scss/static_parser.rb +298 -1
  49. data/lib/sass/selector/abstract_sequence.rb +28 -13
  50. data/lib/sass/selector/comma_sequence.rb +92 -13
  51. data/lib/sass/selector/pseudo.rb +256 -0
  52. data/lib/sass/selector/sequence.rb +94 -24
  53. data/lib/sass/selector/simple.rb +14 -25
  54. data/lib/sass/selector/simple_sequence.rb +97 -33
  55. data/lib/sass/selector.rb +57 -194
  56. data/lib/sass/shared.rb +1 -1
  57. data/lib/sass/source/map.rb +26 -12
  58. data/lib/sass/stack.rb +0 -6
  59. data/lib/sass/supports.rb +2 -3
  60. data/lib/sass/tree/at_root_node.rb +1 -0
  61. data/lib/sass/tree/charset_node.rb +1 -1
  62. data/lib/sass/tree/directive_node.rb +8 -2
  63. data/lib/sass/tree/error_node.rb +18 -0
  64. data/lib/sass/tree/extend_node.rb +1 -1
  65. data/lib/sass/tree/function_node.rb +4 -0
  66. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  67. data/lib/sass/tree/prop_node.rb +1 -1
  68. data/lib/sass/tree/rule_node.rb +12 -7
  69. data/lib/sass/tree/visitors/check_nesting.rb +38 -10
  70. data/lib/sass/tree/visitors/convert.rb +16 -18
  71. data/lib/sass/tree/visitors/cssize.rb +29 -29
  72. data/lib/sass/tree/visitors/deep_copy.rb +5 -0
  73. data/lib/sass/tree/visitors/perform.rb +45 -33
  74. data/lib/sass/tree/visitors/set_options.rb +14 -0
  75. data/lib/sass/tree/visitors/to_css.rb +15 -14
  76. data/lib/sass/util/subset_map.rb +1 -1
  77. data/lib/sass/util.rb +222 -99
  78. data/lib/sass/version.rb +5 -5
  79. data/lib/sass.rb +0 -5
  80. data/test/sass/cache_test.rb +62 -20
  81. data/test/sass/callbacks_test.rb +1 -1
  82. data/test/sass/compiler_test.rb +19 -10
  83. data/test/sass/conversion_test.rb +58 -1
  84. data/test/sass/css2sass_test.rb +23 -4
  85. data/test/sass/encoding_test.rb +219 -0
  86. data/test/sass/engine_test.rb +136 -199
  87. data/test/sass/exec_test.rb +2 -2
  88. data/test/sass/extend_test.rb +236 -19
  89. data/test/sass/functions_test.rb +295 -253
  90. data/test/sass/importer_test.rb +31 -21
  91. data/test/sass/logger_test.rb +1 -1
  92. data/test/sass/more_results/more_import.css +1 -1
  93. data/test/sass/plugin_test.rb +14 -13
  94. data/test/sass/results/compact.css +1 -1
  95. data/test/sass/results/complex.css +4 -4
  96. data/test/sass/results/expanded.css +1 -1
  97. data/test/sass/results/import.css +1 -1
  98. data/test/sass/results/import_charset_ibm866.css +2 -2
  99. data/test/sass/results/mixins.css +17 -17
  100. data/test/sass/results/nested.css +1 -1
  101. data/test/sass/results/parent_ref.css +2 -2
  102. data/test/sass/results/script.css +3 -3
  103. data/test/sass/results/scss_import.css +1 -1
  104. data/test/sass/script_conversion_test.rb +10 -7
  105. data/test/sass/script_test.rb +288 -74
  106. data/test/sass/scss/css_test.rb +141 -24
  107. data/test/sass/scss/rx_test.rb +4 -4
  108. data/test/sass/scss/scss_test.rb +457 -18
  109. data/test/sass/source_map_test.rb +115 -25
  110. data/test/sass/superselector_test.rb +191 -0
  111. data/test/sass/templates/scss_import.scss +2 -1
  112. data/test/sass/test_helper.rb +1 -1
  113. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  114. data/test/sass/util/normalized_map_test.rb +1 -1
  115. data/test/sass/util/subset_map_test.rb +2 -2
  116. data/test/sass/util_test.rb +31 -1
  117. data/test/sass/value_helpers_test.rb +5 -7
  118. data/test/test_helper.rb +2 -2
  119. data/vendor/listen/CHANGELOG.md +1 -228
  120. data/vendor/listen/Gemfile +5 -15
  121. data/vendor/listen/README.md +111 -77
  122. data/vendor/listen/Rakefile +0 -42
  123. data/vendor/listen/lib/listen/adapter.rb +195 -82
  124. data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
  125. data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
  126. data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
  127. data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
  128. data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
  129. data/vendor/listen/lib/listen/directory_record.rb +96 -61
  130. data/vendor/listen/lib/listen/listener.rb +135 -37
  131. data/vendor/listen/lib/listen/turnstile.rb +9 -5
  132. data/vendor/listen/lib/listen/version.rb +1 -1
  133. data/vendor/listen/lib/listen.rb +33 -19
  134. data/vendor/listen/listen.gemspec +6 -0
  135. data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
  136. data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
  137. data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
  138. data/vendor/listen/spec/listen/listener_spec.rb +128 -39
  139. data/vendor/listen/spec/listen_spec.rb +15 -21
  140. data/vendor/listen/spec/spec_helper.rb +4 -0
  141. data/vendor/listen/spec/support/adapter_helper.rb +52 -15
  142. data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
  143. data/vendor/listen/spec/support/listeners_helper.rb +30 -7
  144. metadata +25 -22
  145. data/ext/mkrf_conf.rb +0 -27
  146. data/lib/sass/importers/deprecated_path.rb +0 -51
  147. data/lib/sass/script/value/deprecated_false.rb +0 -55
  148. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  149. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  150. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  151. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -9,7 +9,7 @@ describe Listen::DirectoryRecord do
9
9
  describe '.generate_default_ignoring_patterns' do
10
10
  it 'creates regexp patterns from the default ignored directories and extensions' do
11
11
  described_class.generate_default_ignoring_patterns.should include(
12
- %r{^(?:\.rbx|\.bundle|\.git|\.svn|log|tmp|vendor)/},
12
+ %r{^(?:\.rbx|\.bundle|\.git|\.svn|bundle|log|tmp|vendor)/},
13
13
  %r{(?:\.DS_Store)$}
14
14
  )
15
15
  end
@@ -24,6 +24,12 @@ describe Listen::DirectoryRecord do
24
24
  subject.directory.should eq base_directory
25
25
  end
26
26
 
27
+ it 'sets the base directory expanded' do
28
+ cd File.dirname(base_directory)
29
+ subject = described_class.new(File.basename(base_directory))
30
+ subject.directory.should eq base_directory
31
+ end
32
+
27
33
  it 'sets the default ignoring patterns' do
28
34
  subject.ignoring_patterns.should =~ described_class.generate_default_ignoring_patterns
29
35
  end
@@ -43,28 +49,31 @@ describe Listen::DirectoryRecord do
43
49
 
44
50
  describe '#ignore' do
45
51
  it 'adds the passed paths to the list of ignored paths in the record' do
46
- subject.ignore(%r{^\.old/}, %r{\.pid$})
52
+ subject.ignore(%r{^\.old/}, %r{\.pid$}, nil)
47
53
  subject.ignoring_patterns.should include(%r{^\.old/}, %r{\.pid$})
54
+ subject.ignoring_patterns.should_not include(nil)
48
55
  end
49
56
  end
50
57
 
51
58
  describe '#ignore!' do
52
59
  it 'replace the ignored paths in the record' do
53
- subject.ignore!(%r{^\.old/}, %r{\.pid$})
54
- subject.ignoring_patterns.should =~ [%r{^\.old/}, %r{\.pid$}]
60
+ subject.ignore!(%r{^\.old/}, %r{\.pid$}, nil)
61
+ subject.ignoring_patterns.should eq [%r{^\.old/}, %r{\.pid$}]
55
62
  end
56
63
  end
57
64
 
58
65
  describe '#filter' do
59
66
  it 'adds the passed regexps to the list of filters that determine the stored paths' do
60
- subject.filter(%r{\.(?:jpe?g|gif|png)}, %r{\.(?:mp3|ogg|a3c)})
67
+ subject.filter(%r{\.(?:jpe?g|gif|png)}, %r{\.(?:mp3|ogg|a3c)}, nil)
61
68
  subject.filtering_patterns.should include(%r{\.(?:jpe?g|gif|png)}, %r{\.(?:mp3|ogg|a3c)})
69
+ subject.filtering_patterns.should_not include(nil)
62
70
  end
63
71
  end
64
72
 
65
73
  describe '#filter!' do
66
74
  it 'replaces the passed regexps in the list of filters that determine the stored paths' do
67
75
  subject.filter!(%r{\.(?:jpe?g|gif|png)}, %r{\.(?:mp3|ogg|a3c)})
76
+ subject.filtering_patterns.should have(2).regexps
68
77
  subject.filtering_patterns.should =~ [%r{\.(?:mp3|ogg|a3c)}, %r{\.(?:jpe?g|gif|png)}]
69
78
  end
70
79
  end
@@ -214,6 +223,21 @@ describe Listen::DirectoryRecord do
214
223
  subject.relative_to_base(File.join(base_directory, path))
215
224
  end
216
225
 
226
+ context 'when there are utf-8 chars in base directory' do
227
+ before do
228
+ fixtures do |path|
229
+ mkdir '目录'
230
+ @dir = described_class.new(path + '/目录')
231
+ @dir.build
232
+ end
233
+ end
234
+
235
+ it 'works' do
236
+ path = File.join @dir.directory, 'tmp/file.rb'
237
+ @dir.relative_to_base path
238
+ end
239
+ end
240
+
217
241
  context 'when containing regexp characters in the base directory' do
218
242
  before do
219
243
  fixtures do |path|
@@ -394,7 +418,7 @@ describe Listen::DirectoryRecord do
394
418
  touch 'existing_file.txt'
395
419
 
396
420
  modified, added, removed = changes(path) do
397
- sleep 1.5 # make a difference in the mtime of the file
421
+ small_time_difference
398
422
  touch 'existing_file.txt'
399
423
  end
400
424
 
@@ -414,7 +438,7 @@ describe Listen::DirectoryRecord do
414
438
  touch 'existing_file.txt'
415
439
 
416
440
  modified, added, removed = changes(path) do
417
- sleep 0.3 # make sure the mtime is changed a bit
441
+ small_time_difference
418
442
  touch 'existing_file.txt'
419
443
  end
420
444
 
@@ -428,7 +452,7 @@ describe Listen::DirectoryRecord do
428
452
  # This issue was the result of checking a file for content changes when
429
453
  # the mtime and the checking time are the same. In this case there
430
454
  # is no checksum saved, so the file was reported as being changed.
431
- it ' does not report any changes' do
455
+ it 'does not report any changes' do
432
456
  fixtures do |path|
433
457
  touch 'a_file.rb'
434
458
 
@@ -441,34 +465,17 @@ describe Listen::DirectoryRecord do
441
465
  end
442
466
  end
443
467
 
444
- it "doesn't detects the modified file the second time if the content haven't changed" do
445
- fixtures do |path|
446
- touch 'existing_file.txt'
447
-
448
- changes(path) do
449
- touch 'existing_file.txt'
450
- end
451
-
452
- modified, added, removed = changes(path, :use_last_record => true) do
453
- touch 'existing_file.txt'
454
- end
455
-
456
- added.should be_empty
457
- modified.should be_empty
458
- removed.should be_empty
459
- end
460
- end
461
-
462
468
  it 'detects the modified file the second time if the content have changed' do
463
469
  fixtures do |path|
464
470
  touch 'existing_file.txt'
471
+
465
472
  # Set sha1 path checksum
466
473
  changes(path) do
467
474
  touch 'existing_file.txt'
468
475
  end
469
- small_time_difference
470
476
 
471
477
  changes(path) do
478
+ small_time_difference
472
479
  touch 'existing_file.txt'
473
480
  end
474
481
 
@@ -482,16 +489,36 @@ describe Listen::DirectoryRecord do
482
489
  end
483
490
  end
484
491
 
485
- it "doesn't detects the modified file the second time if just touched - #62" do
492
+ it "doesn't checksum the contents of local sockets (#85)", :unless => windows? do
493
+ require 'socket'
494
+ fixtures do |path|
495
+ Digest::SHA1.should_not_receive(:file)
496
+ socket_path = File.join(path, "unix_domain_socket")
497
+ server = UNIXServer.new(socket_path)
498
+ modified, added, removed = changes(path) do
499
+ t = Thread.new do
500
+ client = UNIXSocket.new(socket_path)
501
+ client.write("foo")
502
+ end
503
+ t.join
504
+ end
505
+ added.should be_empty
506
+ modified.should be_empty
507
+ removed.should be_empty
508
+ end
509
+ end
510
+
511
+ it "doesn't detects the modified file the second time if just touched - #62", :unless => described_class::HIGH_PRECISION_SUPPORTED do
486
512
  fixtures do |path|
487
513
  touch 'existing_file.txt'
514
+
488
515
  # Set sha1 path checksum
489
516
  changes(path) do
490
517
  touch 'existing_file.txt'
491
518
  end
492
- small_time_difference
493
519
 
494
520
  changes(path, :use_last_record => true) do
521
+ small_time_difference
495
522
  open('existing_file.txt', 'w') { |f| f.write('foo') }
496
523
  end
497
524
 
@@ -508,9 +535,9 @@ describe Listen::DirectoryRecord do
508
535
  it "adds the path in the paths checksums if just touched - #62" do
509
536
  fixtures do |path|
510
537
  touch 'existing_file.txt'
511
- small_time_difference
512
538
 
513
539
  changes(path) do
540
+ small_time_difference
514
541
  touch 'existing_file.txt'
515
542
  end
516
543
 
@@ -518,23 +545,21 @@ describe Listen::DirectoryRecord do
518
545
  end
519
546
  end
520
547
 
521
- it "deletes the path from the paths checksums" do
522
- fixtures do |path|
523
- touch 'unnecessary.txt'
548
+ it "deletes the path from the paths checksums" do
549
+ fixtures do |path|
550
+ touch 'unnecessary.txt'
524
551
 
525
- changes(path) do
526
- @record.sha1_checksums["#{path}/unnecessary.txt"] = 'foo'
552
+ changes(path) do
553
+ @record.sha1_checksums["#{path}/unnecessary.txt"] = 'foo'
527
554
 
528
- rm 'unnecessary.txt'
529
- end
555
+ rm 'unnecessary.txt'
556
+ end
530
557
 
531
- @record.sha1_checksums["#{path}/unnecessary.txt"].should be_nil
558
+ @record.sha1_checksums["#{path}/unnecessary.txt"].should be_nil
559
+ end
532
560
  end
533
561
  end
534
562
 
535
-
536
- end
537
-
538
563
  context 'given a hidden file' do
539
564
  it 'detects the modified file' do
540
565
  fixtures do |path|
@@ -556,9 +581,9 @@ describe Listen::DirectoryRecord do
556
581
  it 'does not detect the mode change' do
557
582
  fixtures do |path|
558
583
  touch 'run.rb'
559
- sleep 1.5 # make a difference in the mtime of the file
560
584
 
561
585
  modified, added, removed = changes(path) do
586
+ small_time_difference
562
587
  chmod 0777, 'run.rb'
563
588
  end
564
589
 
@@ -985,9 +1010,8 @@ describe Listen::DirectoryRecord do
985
1010
  touch 'a_directory/a_file.rb'
986
1011
  touch 'a_directory/b_file.rb'
987
1012
 
988
- small_time_difference
989
-
990
1013
  modified, added, removed = changes(path) do
1014
+ small_time_difference
991
1015
  touch 'b_file.rb'
992
1016
  touch 'a_directory/a_file.rb'
993
1017
  end
@@ -1022,16 +1046,18 @@ describe Listen::DirectoryRecord do
1022
1046
  it 'detects a moved directory' do
1023
1047
  fixtures do |path|
1024
1048
  mkdir 'a_directory'
1049
+ mkdir 'a_directory/nested'
1025
1050
  touch 'a_directory/a_file.rb'
1026
1051
  touch 'a_directory/b_file.rb'
1052
+ touch 'a_directory/nested/c_file.rb'
1027
1053
 
1028
1054
  modified, added, removed = changes(path) do
1029
1055
  mv 'a_directory', 'renamed'
1030
1056
  end
1031
1057
 
1032
- added.should =~ %w(renamed/a_file.rb renamed/b_file.rb)
1058
+ added.should =~ %w(renamed/a_file.rb renamed/b_file.rb renamed/nested/c_file.rb)
1033
1059
  modified.should be_empty
1034
- removed.should =~ %w(a_directory/a_file.rb a_directory/b_file.rb)
1060
+ removed.should =~ %w(a_directory/a_file.rb a_directory/b_file.rb a_directory/nested/c_file.rb)
1035
1061
  end
1036
1062
  end
1037
1063
 
@@ -1134,7 +1160,7 @@ describe Listen::DirectoryRecord do
1134
1160
  chmod 000, 'unreadable_file.txt'
1135
1161
 
1136
1162
  modified, added, removed = changes(path) do
1137
- sleep 1.1
1163
+ small_time_difference
1138
1164
  touch 'unreadable_file.txt'
1139
1165
  end
1140
1166
 
@@ -1171,22 +1197,21 @@ describe Listen::DirectoryRecord do
1171
1197
  # change event is tracked, but before the hash is calculated
1172
1198
  Digest::SHA1.should_receive(:file).twice.and_raise(Errno::ENOENT)
1173
1199
 
1174
- lambda {
1175
- fixtures do |path|
1176
- file = 'removed_file.txt'
1177
- touch file
1178
- changes(path) { touch file }
1179
- end
1180
- }.should_not raise_error(Errno::ENOENT)
1200
+ fixtures do |path|
1201
+ lambda {
1202
+ touch 'removed_file.txt'
1203
+ changes(path) { touch 'removed_file.txt' }
1204
+ }.should_not raise_error
1205
+ end
1181
1206
  end
1182
1207
  end
1183
1208
 
1184
- context 'within a directory containing a unix domain socket file' do
1209
+ context 'within a directory containing a unix domain socket file', :unless => windows? do
1185
1210
  it 'does not raise an exception when hashing a unix domain socket file' do
1186
1211
  fixtures do |path|
1187
1212
  require 'socket'
1188
1213
  UNIXServer.new('unix_domain_socket.sock')
1189
- lambda { changes(path){} }.should_not raise_error(Errno::ENXIO)
1214
+ lambda { changes(path){} }.should_not raise_error
1190
1215
  end
1191
1216
  end
1192
1217
  end
@@ -1,64 +1,131 @@
1
1
  require 'spec_helper'
2
2
 
3
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) }
4
+ let(:adapter) { double(Listen::Adapter, :start => true).as_null_object }
5
+ let(:watched_directories) { [File.dirname(__FILE__), File.expand_path('../..', __FILE__)] }
8
6
 
9
7
  before do
10
8
  Listen::Adapter.stub(:select_and_initialize) { adapter }
11
9
  # Don't build a record of the files inside the base directory.
12
- subject.directory_record.stub(:build)
10
+ Listen::DirectoryRecord.any_instance.stub(:build)
11
+ Kernel.stub(:warn)
13
12
  end
13
+ subject { described_class.new(watched_directories) }
14
14
 
15
15
  it_should_behave_like 'a listener to changes on a file-system'
16
16
 
17
17
  describe '#initialize' do
18
- context 'with no options' do
19
- it 'sets the directory' do
20
- subject.directory.should eq watched_directory
18
+ context 'listening to a single directory' do
19
+ let(:watched_directory) { File.dirname(__FILE__) }
20
+ let(:watched_directories) { nil }
21
+ subject { described_class.new(watched_directory) }
22
+
23
+ it 'sets the directories' do
24
+ subject.directories.should eq [watched_directory]
21
25
  end
22
26
 
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)
27
+ context 'with no options' do
28
+ it 'sets the option for using relative paths in the callback to false' do
29
+ subject.instance_variable_get(:@use_relative_paths).should eq false
30
+ end
31
+ end
32
+
33
+ context 'with :relative_paths => false' do
34
+ it 'sets the option for using relative paths in the callback to false' do
35
+ listener = described_class.new(watched_directory, :relative_paths => false)
36
+ listener.instance_variable_get(:@use_relative_paths).should eq false
37
+ end
38
+ end
39
+
40
+ context 'with :relative_paths => true' do
41
+ it 'sets the option for using relative paths in the callback to true' do
42
+ listener = described_class.new(watched_directory, :relative_paths => true)
43
+ listener.instance_variable_get(:@use_relative_paths).should eq true
44
+ end
45
+ end
46
+ end
47
+
48
+ context 'listening to multiple directories' do
49
+ subject { described_class.new(watched_directories) }
50
+
51
+ it 'sets the directories' do
52
+ subject.directories.should eq watched_directories
53
+ end
54
+
55
+ context 'with no options' do
56
+ it 'sets the option for using relative paths in the callback to false' do
57
+ subject.instance_variable_get(:@use_relative_paths).should eq false
58
+ end
59
+ end
60
+
61
+ context 'with :relative_paths => false' do
62
+ it 'sets the option for using relative paths in the callback to false' do
63
+ listener = described_class.new(watched_directories, :relative_paths => false)
64
+ listener.instance_variable_get(:@use_relative_paths).should eq false
65
+ end
66
+ end
67
+
68
+ context 'with :relative_paths => true' do
69
+ it 'warns' do
70
+ Kernel.should_receive(:warn).with("[Listen warning]: #{Listen::Listener::RELATIVE_PATHS_WITH_MULTIPLE_DIRECTORIES_WARNING_MESSAGE}")
71
+ listener = described_class.new(watched_directories, :relative_paths => true)
72
+ end
73
+
74
+ it 'sets the option for using relative paths in the callback to false' do
75
+ listener = described_class.new(watched_directories, :relative_paths => true)
76
+ listener.instance_variable_get(:@use_relative_paths).should eq false
77
+ end
25
78
  end
79
+ end
26
80
 
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
81
+ context 'with a directory' do
82
+ let(:watched_directory) { File.dirname(__FILE__) }
83
+ it 'converts the passed path into an absolute path - #21' do
84
+ described_class.new(File.join(watched_directory, '..')).directories.should eq [File.expand_path('..', watched_directory)]
29
85
  end
30
86
  end
31
87
 
32
88
  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) }
89
+ let(:watched_directory) { File.dirname(__FILE__) }
90
+ let(:adapter_class) { double('adapter class') }
35
91
 
36
- it 'passes the custom ignored paths to the directory record' do
37
- subject.directory_record.ignoring_patterns.should include /\.ssh/
92
+ let(:options) do
93
+ {
94
+ :ignore => /\.ssh/, :filter => [/.*\.rb/, /.*\.md/],
95
+ :latency => 0.5, :force_polling => true, :relative_paths => true,
96
+ :force_adapter => adapter_class
97
+ }
38
98
  end
99
+ subject { described_class.new(watched_directory, options) }
39
100
 
40
- it 'passes the custom filters to the directory record' do
41
- subject.directory_record.filtering_patterns.should =~ [/.*\.rb/,/.*\.md/]
101
+ it 'passes the custom ignored paths to the directory record' do
102
+ subject.directories_records.each do |directory_record|
103
+ directory_record.ignoring_patterns.should include /\.ssh/
104
+ end
42
105
  end
43
106
 
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
107
+ it 'passes the custom filters to the directory record' do
108
+ subject.directories_records.each do |directory_record|
109
+ directory_record.filtering_patterns.should =~ [/.*\.rb/,/.*\.md/]
110
+ end
46
111
  end
47
112
 
48
113
  it 'sets adapter_options' do
49
- subject.instance_variable_get(:@adapter_options).should eq(:latency => 0.5, :force_polling => true)
114
+ subject.instance_variable_get(:@adapter_options).should eq(:latency => 0.5, :force_polling => true, :force_adapter => adapter_class)
50
115
  end
51
116
  end
52
117
  end
53
118
 
54
119
  describe '#start' do
55
120
  it 'selects and initializes an adapter' do
56
- Listen::Adapter.should_receive(:select_and_initialize).with(watched_directory, {}) { adapter }
121
+ Listen::Adapter.should_receive(:select_and_initialize).with(watched_directories, {}) { adapter }
57
122
  subject.start
58
123
  end
59
124
 
60
125
  it 'builds the directory record' do
61
- subject.directory_record.should_receive(:build)
126
+ subject.directories_records.each do |directory_record|
127
+ directory_record.should_receive(:build)
128
+ end
62
129
  subject.start
63
130
  end
64
131
  end
@@ -71,7 +138,9 @@ describe Listen::Listener do
71
138
 
72
139
  describe '#unpause' do
73
140
  it 'rebuilds the directory record' do
74
- subject.directory_record.should_receive(:build)
141
+ subject.directories_records.each do |directory_record|
142
+ directory_record.should_receive(:build)
143
+ end
75
144
  subject.unpause
76
145
  end
77
146
  end
@@ -79,33 +148,40 @@ describe Listen::Listener do
79
148
 
80
149
  describe '#ignore'do
81
150
  it 'delegates the work to the directory record' do
82
- subject.directory_record.should_receive(:ignore).with 'some_directory'
151
+ subject.directories_records.each do |directory_record|
152
+ directory_record.should_receive(:ignore).with 'some_directory'
153
+ end
83
154
  subject.ignore 'some_directory'
84
155
  end
85
156
  end
86
157
 
87
158
  describe '#ignore!'do
88
159
  it 'delegates the work to the directory record' do
89
- subject.directory_record.should_receive(:ignore!).with 'some_directory'
160
+ subject.directories_records.each do |directory_record|
161
+ directory_record.should_receive(:ignore!).with 'some_directory'
162
+ end
90
163
  subject.ignore! 'some_directory'
91
164
  end
92
165
  end
93
166
 
94
167
  describe '#filter' do
95
168
  it 'delegates the work to the directory record' do
96
- subject.directory_record.should_receive(:filter).with /\.txt$/
169
+ subject.directories_records.each do |directory_record|
170
+ directory_record.should_receive(:filter).with /\.txt$/
171
+ end
97
172
  subject.filter /\.txt$/
98
173
  end
99
174
  end
100
175
 
101
176
  describe '#filter!' do
102
177
  it 'delegates the work to the directory record' do
103
- subject.directory_record.should_receive(:filter!).with /\.txt$/
178
+ subject.directories_records.each do |directory_record|
179
+ directory_record.should_receive(:filter!).with /\.txt$/
180
+ end
104
181
  subject.filter! /\.txt$/
105
182
  end
106
183
  end
107
184
 
108
-
109
185
  describe '#on_change' do
110
186
  let(:directories) { %w{dir1 dir2 dir3} }
111
187
  let(:changes) { {:modified => [], :added => [], :removed => []} }
@@ -113,23 +189,32 @@ describe Listen::Listener do
113
189
 
114
190
  before do
115
191
  @called = false
116
- subject.directory_record.stub(:fetch_changes => changes)
192
+ subject.stub(:fetch_records_changes => changes)
117
193
  end
118
194
 
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
- )
195
+ it 'fetches the changes of all directories records' do
196
+ subject.unstub(:fetch_records_changes)
197
+
198
+ subject.directories_records.each do |record|
199
+ record.should_receive(:fetch_changes).with(directories, an_instance_of(Hash)).and_return(changes)
200
+ end
123
201
  subject.on_change(directories)
124
202
  end
125
203
 
126
- context 'with relative paths option set to true' do
127
- subject { described_class.new(watched_directory, :relative_paths => true) }
204
+ context "with a callback raising an exception" do
205
+ let(:callback) { Proc.new { raise 'foo' } }
206
+
207
+ before do
208
+ subject.change(&callback)
209
+ subject.stub(:fetch_records_changes => { :modified => ['foo'], :added => [], :removed => [] } )
210
+ end
128
211
 
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))
212
+ it "stops the adapter and warns" do
213
+ Kernel.should_receive(:warn).with("[Listen warning]: Change block raise an execption: foo")
214
+ Kernel.should_receive(:warn).with(/^Backtrace:.*/)
131
215
  subject.on_change(directories)
132
216
  end
217
+
133
218
  end
134
219
 
135
220
  context 'with no changes to report' do
@@ -149,7 +234,11 @@ describe Listen::Listener do
149
234
  end
150
235
 
151
236
  context 'with changes to report' do
152
- let(:changes) { {:modified => %w{path1}, :added => [], :removed => %w{path2}} }
237
+ let(:changes) do
238
+ {
239
+ :modified => %w{path1}, :added => [], :removed => %w{path2}
240
+ }
241
+ end
153
242
 
154
243
  if RUBY_VERSION[/^1.8/]
155
244
  it 'runs the callback passing it the changes' do
@@ -2,21 +2,20 @@ require 'spec_helper'
2
2
 
3
3
  describe Listen do
4
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) }
5
+ let(:listener) { double(Listen::Listener) }
6
+ let(:listener_class) { Listen::Listener }
7
+ before { listener_class.stub(:new => listener) }
10
8
 
9
+ context 'with one path to listen to' do
11
10
  context 'without options' do
12
- it 'creates an instance of Listner' do
11
+ it 'creates an instance of Listener' do
13
12
  listener_class.should_receive(:new).with('/path')
14
13
  described_class.to('/path')
15
14
  end
16
15
  end
17
16
 
18
17
  context 'with options' do
19
- it 'creates an instance of Listner with the passed params' do
18
+ it 'creates an instance of Listener with the passed params' do
20
19
  listener_class.should_receive(:new).with('/path', :filter => '**/*')
21
20
  described_class.to('/path', :filter => '**/*')
22
21
  end
@@ -29,7 +28,7 @@ describe Listen do
29
28
  end
30
29
 
31
30
  context 'with a block' do
32
- it 'starts the listner after creating it' do
31
+ it 'starts the listener after creating it' do
33
32
  listener.should_receive(:start)
34
33
  described_class.to('/path', :filter => '**/*') { |modified, added, removed| }
35
34
  end
@@ -37,34 +36,29 @@ describe Listen do
37
36
  end
38
37
 
39
38
  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
39
  context 'without options' do
46
- it 'creates an instance of MultiListner' do
47
- multi_listener_class.should_receive(:new).with('path1', 'path2')
40
+ it 'creates an instance of Listener' do
41
+ listener_class.should_receive(:new).with('path1', 'path2')
48
42
  described_class.to('path1', 'path2')
49
43
  end
50
44
  end
51
45
 
52
46
  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 => '**/*')
47
+ it 'creates an instance of Listener with the passed params' do
48
+ listener_class.should_receive(:new).with('path1', 'path2', :filter => '**/*')
55
49
  described_class.to('path1', 'path2', :filter => '**/*')
56
50
  end
57
51
  end
58
52
 
59
53
  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
54
+ it 'returns a Listener instance created with the passed params' do
55
+ described_class.to('path1', 'path2', :filter => '**/*').should eq listener
62
56
  end
63
57
  end
64
58
 
65
59
  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)
60
+ it 'starts a Listener instance after creating it with the passed params' do
61
+ listener.should_receive(:start)
68
62
  described_class.to('path1', 'path2', :filter => '**/*') { |modified, added, removed| }
69
63
  end
70
64
  end
@@ -1,3 +1,7 @@
1
+ require 'rubygems'
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+
1
5
  require 'listen'
2
6
 
3
7
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }