├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── BSDL ├── COPYING ├── Gemfile ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── find.gemspec ├── lib └── find.rb └── test ├── lib └── helper.rb └── test_find.rb /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'weekly' 7 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | ruby-versions: 7 | uses: ruby/actions/.github/workflows/ruby_versions.yml@master 8 | with: 9 | engine: cruby 10 | min_version: 2.5 11 | 12 | test: 13 | needs: ruby-versions 14 | name: build (${{ matrix.ruby }} / ${{ matrix.os }}) 15 | strategy: 16 | matrix: 17 | ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} 18 | os: [ ubuntu-latest, macos-latest, windows-latest ] 19 | exclude: 20 | - ruby: 2.5 21 | os: macos-latest 22 | runs-on: ${{ matrix.os }} 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | - name: Run test 31 | run: bundle exec rake test 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | -------------------------------------------------------------------------------- /BSDL: -------------------------------------------------------------------------------- 1 | Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Ruby is copyrighted free software by Yukihiro Matsumoto . 2 | You can redistribute it and/or modify it under either the terms of the 3 | 2-clause BSDL (see the file BSDL), or the conditions below: 4 | 5 | 1. You may make and give away verbatim copies of the source form of the 6 | software without restriction, provided that you duplicate all of the 7 | original copyright notices and associated disclaimers. 8 | 9 | 2. You may modify your copy of the software in any way, provided that 10 | you do at least ONE of the following: 11 | 12 | a. place your modifications in the Public Domain or otherwise 13 | make them Freely Available, such as by posting said 14 | modifications to Usenet or an equivalent medium, or by allowing 15 | the author to include your modifications in the software. 16 | 17 | b. use the modified software only within your corporation or 18 | organization. 19 | 20 | c. give non-standard binaries non-standard names, with 21 | instructions on where to get the original software distribution. 22 | 23 | d. make other distribution arrangements with the author. 24 | 25 | 3. You may distribute the software in object code or binary form, 26 | provided that you do at least ONE of the following: 27 | 28 | a. distribute the binaries and library files of the software, 29 | together with instructions (in the manual page or equivalent) 30 | on where to get the original distribution. 31 | 32 | b. accompany the distribution with the machine-readable source of 33 | the software. 34 | 35 | c. give non-standard binaries non-standard names, with 36 | instructions on where to get the original software distribution. 37 | 38 | d. make other distribution arrangements with the author. 39 | 40 | 4. You may modify and include the part of the software into any other 41 | software (possibly commercial). But some files in the distribution 42 | are not written by the author, so that they are not under these terms. 43 | 44 | For the list of those files and their copying conditions, see the 45 | file LEGAL. 46 | 47 | 5. The scripts and library files supplied as input to or produced as 48 | output from the software do not automatically fall under the 49 | copyright of the software, but belong to whomever generated them, 50 | and may be sold commercially, and may be aggregated with this 51 | software. 52 | 53 | 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 54 | IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 55 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 56 | PURPOSE. 57 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "rake" 4 | gem "test-unit" 5 | gem "test-unit-ruby-core" 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Find 2 | 3 | The +Find+ module supports the top-down traversal of a set of file paths. 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | ```ruby 10 | gem 'find' 11 | ``` 12 | 13 | And then execute: 14 | 15 | $ bundle install 16 | 17 | Or install it yourself as: 18 | 19 | $ gem install find 20 | 21 | ## Usage 22 | 23 | For example, to total the size of all files under your home directory, 24 | ignoring anything in a "dot" directory (e.g. $HOME/.ssh): 25 | 26 | ```ruby 27 | require 'find' 28 | 29 | total_size = 0 30 | 31 | Find.find(ENV["HOME"]) do |path| 32 | if FileTest.directory?(path) 33 | if File.basename(path).start_with?('.') 34 | Find.prune # Don't look any further into this directory. 35 | else 36 | next 37 | end 38 | else 39 | total_size += FileTest.size(path) 40 | end 41 | end 42 | ``` 43 | 44 | ## Development 45 | 46 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 47 | 48 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 49 | 50 | ## Contributing 51 | 52 | Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/find. 53 | 54 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << "test/lib" 6 | t.ruby_opts << "-rhelper" 7 | t.test_files = FileList["test/**/test_*.rb"] 8 | end 9 | 10 | task :default => :test 11 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "find" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /find.gemspec: -------------------------------------------------------------------------------- 1 | name = File.basename(__FILE__, ".gemspec") 2 | version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir| 3 | break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line| 4 | /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1 5 | end rescue nil 6 | end 7 | 8 | Gem::Specification.new do |spec| 9 | spec.name = name 10 | spec.version = version 11 | spec.authors = ['Kazuki Tsujimoto'] 12 | spec.email = ['kazuki@callcc.net'] 13 | 14 | spec.summary = %q{This module supports top-down traversal of a set of file paths.} 15 | spec.description = %q{This module supports top-down traversal of a set of file paths.} 16 | spec.homepage = "https://github.com/ruby/find" 17 | spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0") 18 | spec.licenses = ["Ruby", "BSD-2-Clause"] 19 | 20 | spec.metadata["homepage_uri"] = spec.homepage 21 | spec.metadata["source_code_uri"] = spec.homepage 22 | 23 | # Specify which files should be added to the gem when it is released. 24 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 25 | spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do 26 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 27 | end 28 | spec.require_paths = ["lib"] 29 | end 30 | -------------------------------------------------------------------------------- /lib/find.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # 3 | # find.rb: the Find module for processing all files under a given directory. 4 | # 5 | 6 | # 7 | # The +Find+ module supports the top-down traversal of a set of file paths. 8 | # 9 | # For example, to total the size of all files under your home directory, 10 | # ignoring anything in a "dot" directory (e.g. $HOME/.ssh): 11 | # 12 | # require 'find' 13 | # 14 | # total_size = 0 15 | # 16 | # Find.find(ENV["HOME"]) do |path| 17 | # if FileTest.directory?(path) 18 | # if File.basename(path).start_with?('.') 19 | # Find.prune # Don't look any further into this directory. 20 | # else 21 | # next 22 | # end 23 | # else 24 | # total_size += FileTest.size(path) 25 | # end 26 | # end 27 | # 28 | module Find 29 | 30 | VERSION = "0.2.0" 31 | 32 | # 33 | # Calls the associated block with the name of every file and directory listed 34 | # as arguments, then recursively on their subdirectories, and so on. 35 | # 36 | # Returns an enumerator if no block is given. 37 | # 38 | # See the +Find+ module documentation for an example. 39 | # 40 | def find(*paths, ignore_error: true) # :yield: path 41 | block_given? or return enum_for(__method__, *paths, ignore_error: ignore_error) 42 | 43 | fs_encoding = Encoding.find("filesystem") 44 | 45 | paths.collect!{|d| raise Errno::ENOENT, d unless File.exist?(d); d.dup}.each do |path| 46 | path = path.to_path if path.respond_to? :to_path 47 | enc = path.encoding == Encoding::US_ASCII ? fs_encoding : path.encoding 48 | ps = [path] 49 | while file = ps.shift 50 | catch(:prune) do 51 | yield file.dup 52 | begin 53 | s = File.lstat(file) 54 | rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL 55 | raise unless ignore_error 56 | next 57 | end 58 | if s.directory? then 59 | begin 60 | fs = Dir.children(file, encoding: enc) 61 | rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL 62 | raise unless ignore_error 63 | next 64 | end 65 | fs.sort! 66 | fs.reverse_each {|f| 67 | f = File.join(file, f) 68 | ps.unshift f 69 | } 70 | end 71 | end 72 | end 73 | end 74 | nil 75 | end 76 | 77 | # 78 | # Skips the current file or directory, restarting the loop with the next 79 | # entry. If the current file is a directory, that directory will not be 80 | # recursively entered. Meaningful only within the block associated with 81 | # Find::find. 82 | # 83 | # See the +Find+ module documentation for an example. 84 | # 85 | def prune 86 | throw :prune 87 | end 88 | 89 | module_function :find, :prune 90 | end 91 | -------------------------------------------------------------------------------- /test/lib/helper.rb: -------------------------------------------------------------------------------- 1 | require "test/unit" 2 | require "core_assertions" 3 | 4 | Test::Unit::TestCase.include Test::Unit::CoreAssertions 5 | -------------------------------------------------------------------------------- /test/test_find.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'find' 4 | require 'tmpdir' 5 | 6 | class TestFind < Test::Unit::TestCase 7 | def test_empty 8 | Dir.mktmpdir {|d| 9 | a = [] 10 | Find.find(d) {|f| a << f } 11 | assert_equal([d], a) 12 | } 13 | end 14 | 15 | def test_nonexistence 16 | bug12087 = '[ruby-dev:49497] [Bug #12087]' 17 | Dir.mktmpdir {|d| 18 | path = "#{d}/a" 19 | re = /#{Regexp.quote(path)}\z/ 20 | assert_raise_with_message(Errno::ENOENT, re, bug12087) { 21 | Find.find(path) {} 22 | } 23 | } 24 | end 25 | 26 | def test_rec 27 | Dir.mktmpdir {|d| 28 | File.open("#{d}/a", "w"){} 29 | Dir.mkdir("#{d}/b") 30 | File.open("#{d}/b/a", "w"){} 31 | File.open("#{d}/b/b", "w"){} 32 | Dir.mkdir("#{d}/c") 33 | a = [] 34 | Find.find(d) {|f| a << f } 35 | assert_equal([d, "#{d}/a", "#{d}/b", "#{d}/b/a", "#{d}/b/b", "#{d}/c"], a) 36 | } 37 | end 38 | 39 | def test_relative 40 | Dir.mktmpdir {|d| 41 | File.open("#{d}/a", "w"){} 42 | Dir.mkdir("#{d}/b") 43 | File.open("#{d}/b/a", "w"){} 44 | File.open("#{d}/b/b", "w"){} 45 | Dir.mkdir("#{d}/c") 46 | a = [] 47 | Dir.chdir(d) { 48 | Find.find(".") {|f| a << f } 49 | } 50 | assert_equal([".", "./a", "./b", "./b/a", "./b/b", "./c"], a) 51 | } 52 | end 53 | 54 | def test_dont_follow_symlink 55 | Dir.mktmpdir {|d| 56 | File.open("#{d}/a", "w"){} 57 | Dir.mkdir("#{d}/b") 58 | File.open("#{d}/b/a", "w"){} 59 | File.open("#{d}/b/b", "w"){} 60 | begin 61 | File.symlink("#{d}/b", "#{d}/c") 62 | rescue NotImplementedError, Errno::EACCES 63 | omit "symlink is not supported." 64 | end 65 | a = [] 66 | Find.find(d) {|f| a << f } 67 | assert_equal([d, "#{d}/a", "#{d}/b", "#{d}/b/a", "#{d}/b/b", "#{d}/c"], a) 68 | } 69 | end 70 | 71 | def test_prune 72 | Dir.mktmpdir {|d| 73 | File.open("#{d}/a", "w"){} 74 | Dir.mkdir("#{d}/b") 75 | File.open("#{d}/b/a", "w"){} 76 | File.open("#{d}/b/b", "w"){} 77 | Dir.mkdir("#{d}/c") 78 | a = [] 79 | Find.find(d) {|f| 80 | a << f 81 | Find.prune if f == "#{d}/b" 82 | } 83 | assert_equal([d, "#{d}/a", "#{d}/b", "#{d}/c"], a) 84 | } 85 | end 86 | 87 | def test_countup3 88 | Dir.mktmpdir {|d| 89 | 1.upto(3) {|n| File.open("#{d}/#{n}", "w"){} } 90 | a = [] 91 | Find.find(d) {|f| a << f } 92 | assert_equal([d, "#{d}/1", "#{d}/2", "#{d}/3"], a) 93 | } 94 | end 95 | 96 | def test_countdown3 97 | Dir.mktmpdir {|d| 98 | 3.downto(1) {|n| File.open("#{d}/#{n}", "w"){} } 99 | a = [] 100 | Find.find(d) {|f| a << f } 101 | assert_equal([d, "#{d}/1", "#{d}/2", "#{d}/3"], a) 102 | } 103 | end 104 | 105 | def test_unreadable_dir 106 | omit "no meaning test on Windows" if /mswin|mingw/ =~ RUBY_PLATFORM 107 | omit "because root can read anything" if Process.uid == 0 108 | 109 | Dir.mktmpdir {|d| 110 | Dir.mkdir(dir = "#{d}/dir") 111 | File.open("#{dir}/foo", "w"){} 112 | begin 113 | File.chmod(0300, dir) 114 | a = [] 115 | Find.find(d) {|f| a << f } 116 | assert_equal([d, dir], a) 117 | 118 | a = [] 119 | Find.find(d, ignore_error: true) {|f| a << f } 120 | assert_equal([d, dir], a) 121 | 122 | a = [] 123 | Find.find(d, ignore_error: true).each {|f| a << f } 124 | assert_equal([d, dir], a) 125 | 126 | a = [] 127 | assert_raise_with_message(Errno::EACCES, /#{Regexp.quote(dir)}/) do 128 | Find.find(d, ignore_error: false) {|f| a << f } 129 | end 130 | assert_equal([d, dir], a) 131 | 132 | a = [] 133 | assert_raise_with_message(Errno::EACCES, /#{Regexp.quote(dir)}/) do 134 | Find.find(d, ignore_error: false).each {|f| a << f } 135 | end 136 | assert_equal([d, dir], a) 137 | ensure 138 | File.chmod(0700, dir) 139 | end 140 | } 141 | end 142 | 143 | def test_unsearchable_dir 144 | Dir.mktmpdir {|d| 145 | Dir.mkdir(dir = "#{d}/dir") 146 | File.open(file = "#{dir}/foo", "w"){} 147 | begin 148 | File.chmod(0600, dir) 149 | a = [] 150 | Find.find(d) {|f| a << f } 151 | assert_equal([d, dir, file], a) 152 | 153 | a = [] 154 | Find.find(d, ignore_error: true) {|f| a << f } 155 | assert_equal([d, dir, file], a) 156 | 157 | a = [] 158 | Find.find(d, ignore_error: true).each {|f| a << f } 159 | assert_equal([d, dir, file], a) 160 | 161 | omit "no meaning test on Windows" if /mswin|mingw/ =~ RUBY_PLATFORM 162 | omit "skipped because root can read anything" if Process.uid == 0 163 | 164 | a = [] 165 | assert_raise_with_message(Errno::EACCES, /#{Regexp.quote(file)}/) do 166 | Find.find(d, ignore_error: false) {|f| a << f } 167 | end 168 | assert_equal([d, dir, file], a) 169 | 170 | a = [] 171 | assert_raise_with_message(Errno::EACCES, /#{Regexp.quote(file)}/) do 172 | Find.find(d, ignore_error: false).each {|f| a << f } 173 | end 174 | assert_equal([d, dir, file], a) 175 | 176 | assert_raise(Errno::EACCES) { File.lstat(file) } 177 | ensure 178 | File.chmod(0700, dir) 179 | end 180 | } 181 | end 182 | 183 | def test_dangling_symlink 184 | Dir.mktmpdir {|d| 185 | begin 186 | File.symlink("foo", "#{d}/bar") 187 | rescue NotImplementedError, Errno::EACCES 188 | omit "symlink is not supported." 189 | end 190 | a = [] 191 | Find.find(d) {|f| a << f } 192 | assert_equal([d, "#{d}/bar"], a) 193 | assert_raise(Errno::ENOENT) { File.stat("#{d}/bar") } 194 | } 195 | end 196 | 197 | def test_dangling_symlink_stat_error 198 | Dir.mktmpdir {|d| 199 | begin 200 | File.symlink("foo", "#{d}/bar") 201 | rescue NotImplementedError, Errno::EACCES 202 | omit "symlink is not supported." 203 | end 204 | assert_raise(Errno::ENOENT) { 205 | Find.find(d) {|f| File.stat(f) } 206 | } 207 | } 208 | end 209 | 210 | def test_change_dir_to_file 211 | Dir.mktmpdir {|d| 212 | Dir.mkdir(dir_1 = "#{d}/d1") 213 | File.open(file_a = "#{dir_1}/a", "w"){} 214 | File.open(file_b = "#{dir_1}/b", "w"){} 215 | File.open(file_c = "#{dir_1}/c", "w"){} 216 | Dir.mkdir(dir_d = "#{dir_1}/d") 217 | File.open("#{dir_d}/e", "w"){} 218 | dir_2 = "#{d}/d2" 219 | a = [] 220 | Find.find(d) {|f| 221 | a << f 222 | if f == file_b 223 | File.rename(dir_1, dir_2) 224 | File.open(dir_1, "w") {} 225 | end 226 | } 227 | assert_equal([d, dir_1, file_a, file_b, file_c, dir_d], a) 228 | } 229 | end 230 | 231 | def test_change_dir_to_symlink_loop 232 | Dir.mktmpdir {|d| 233 | Dir.mkdir(dir_1 = "#{d}/d1") 234 | File.open(file_a = "#{dir_1}/a", "w"){} 235 | File.open(file_b = "#{dir_1}/b", "w"){} 236 | File.open(file_c = "#{dir_1}/c", "w"){} 237 | Dir.mkdir(dir_d = "#{dir_1}/d") 238 | File.open("#{dir_d}/e", "w"){} 239 | dir_2 = "#{d}/d2" 240 | a = [] 241 | Find.find(d) {|f| 242 | a << f 243 | if f == file_b 244 | File.rename(dir_1, dir_2) 245 | begin 246 | File.symlink("d1", dir_1) 247 | rescue NotImplementedError, Errno::EACCES 248 | omit "symlink is not supported." 249 | end 250 | end 251 | } 252 | assert_equal([d, dir_1, file_a, file_b, file_c, dir_d], a) 253 | } 254 | end 255 | 256 | def test_enumerator 257 | Dir.mktmpdir {|d| 258 | File.open("#{d}/a", "w"){} 259 | Dir.mkdir("#{d}/b") 260 | File.open("#{d}/b/a", "w"){} 261 | File.open("#{d}/b/b", "w"){} 262 | Dir.mkdir("#{d}/c") 263 | e = Find.find(d) 264 | a = [] 265 | e.each {|f| a << f } 266 | assert_equal([d, "#{d}/a", "#{d}/b", "#{d}/b/a", "#{d}/b/b", "#{d}/c"], a) 267 | } 268 | end 269 | 270 | def test_encoding_ascii 271 | Dir.mktmpdir {|d| 272 | File.open("#{d}/a", "w"){} 273 | Dir.mkdir("#{d}/b") 274 | a = [] 275 | Find.find(d.encode(Encoding::US_ASCII)) {|f| a << f } 276 | a.each do |i| 277 | assert(Encoding.compatible?(d.encode(Encoding.find('filesystem')), i)) 278 | end 279 | } 280 | end 281 | 282 | def test_encoding_non_ascii 283 | Dir.mktmpdir {|d| 284 | File.open("#{d}/a", "w"){} 285 | Dir.mkdir("#{d}/b") 286 | euc_jp = Encoding::EUC_JP 287 | win_31j = Encoding::Windows_31J 288 | utf_8 = Encoding::UTF_8 289 | a = [] 290 | Find.find(d.encode(euc_jp), d.encode(win_31j), d.encode(utf_8)) {|f| a << [f, f.encoding] } 291 | assert_equal([[d, euc_jp], ["#{d}/a", euc_jp], ["#{d}/b", euc_jp], 292 | [d, win_31j], ["#{d}/a", win_31j], ["#{d}/b", win_31j], 293 | [d, utf_8], ["#{d}/a", utf_8], ["#{d}/b", utf_8]], 294 | a) 295 | if /mswin|mingw/ =~ RUBY_PLATFORM 296 | a = [] 297 | Dir.mkdir("#{d}/\u{2660}") 298 | Find.find("#{d}".encode(utf_8)) {|f| a << [f, f.encoding] } 299 | assert_equal([[d, utf_8], ["#{d}/a", utf_8], ["#{d}/b", utf_8], ["#{d}/\u{2660}", utf_8]], a) 300 | end 301 | } 302 | end 303 | 304 | def test_to_path 305 | c = Class.new { 306 | def initialize(path) 307 | @path = path 308 | end 309 | 310 | def to_path 311 | @path 312 | end 313 | } 314 | Dir.mktmpdir {|d| 315 | a = [] 316 | Find.find(c.new(d)) {|f| a << f } 317 | assert_equal([d], a) 318 | } 319 | end 320 | 321 | class TestInclude < Test::Unit::TestCase 322 | include Find 323 | 324 | def test_functional_call 325 | Dir.mktmpdir {|d| 326 | File.open("#{d}/a", "w"){} 327 | a = [] 328 | find(d) {|f| a << f } 329 | assert_equal([d, "#{d}/a"], a) 330 | } 331 | end 332 | end 333 | 334 | end 335 | --------------------------------------------------------------------------------