Guest User

Untitled

a guest
Jul 19th, 2018
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.65 KB | None | 0 0
  1. ファイル検索用のインタプリタを作成する過程から、 interpreter パターンを学ぶ
  2.  
  3. ** すべてのファイルを検索する/名前でファイルを検索する/大きなファイル/書き込み可能ファイル
  4.  
  5. require 'find'
  6.  
  7. class Expression
  8. end
  9.  
  10. # すべてのファイルを検索する
  11. class All < Expression
  12. def evaluate(dir)
  13. results= []
  14. Find.find(dir) do |p|
  15. next unless File.file?(p)
  16. results << p
  17. end
  18. results
  19. end
  20. end
  21.  
  22. expr_all = All.new
  23. files = expr_all.evaluate('test_dir')
  24.  
  25. files # => ["test_dir/small2.txt", "test_dir/subdir/small.jpg", "test_dir/subdir/other.mp3", "test_dir/small1.txt", "test_dir/big.mp3", "test_dir/small.mp3", "test_dir/big2.mp3"]
  26.  
  27. # 名前でファイルを検索する
  28. class FileName < Expression
  29. def initialize(pattern)
  30. @pattern = pattern
  31. end
  32.  
  33. def evaluate(dir)
  34. results= []
  35. Find.find(dir) do |p|
  36. next unless File.file?(p)
  37. name = File.basename(p)
  38. results << p if File.fnmatch(@pattern, name)
  39. end
  40. results
  41. end
  42. end
  43.  
  44. expr_mp3 = FileName.new('*.mp3')
  45. mp3s = expr_mp3.evaluate('test_dir')
  46. mp3s # => ["test_dir/subdir/other.mp3", "test_dir/big.mp3", "test_dir/small.mp3", "test_dir/big2.mp3"]
  47.  
  48. # 大きなファイル
  49. class Bigger < Expression
  50. def initialize(size)
  51. @size = size
  52. end
  53.  
  54. def evaluate(dir)
  55. results = []
  56. Find.find(dir) do |p|
  57. next unless File.file?(p)
  58. results << p if( File.size(p) > @size)
  59. end
  60. results
  61. end
  62. end
  63.  
  64. expr_big = Bigger.new(80)
  65. bigs = expr_big.evaluate('test_dir')
  66. bigs # => ["test_dir/subdir/other.mp3", "test_dir/big.mp3", "test_dir/big2.mp3"]
  67.  
  68. #書き込み可能ファイル
  69. class Writable < Expression
  70. def evaluate(dir)
  71. results = []
  72. Find.find(dir) do |p|
  73. next unless File.file?(p)
  74. results << p if( File.writable?(p) )
  75. end
  76. results
  77. end
  78. end
  79.  
  80. expr_writable = Writable.new
  81. writables = expr_writable.evaluate('test_dir')
  82. writables # => ["test_dir/small2.txt", "test_dir/subdir/small.jpg", "test_dir/subdir/other.mp3", "test_dir/small1.txt", "test_dir/big.mp3", "test_dir/small.mp3", "test_dir/big2.mp3"]
  83.  
  84. ** Not,And,Or を使ったより複雑な検索
  85.  
  86. class Not < Expression
  87. def initialize(expression)
  88. @expression = expression
  89. end
  90.  
  91. def evaluate(dir)
  92. All.new.evaluate(dir) - @expression.evaluate(dir)
  93. end
  94. end
  95.  
  96. expr_not_writable = Not.new(Writable.new)
  97. readonly_files = expr_not_writable.evaluate('test_dir')
  98. readonly_files # => ["test_dir/small1.txt"]
  99.  
  100. small_expr = Not.new(Bigger.new(1024))
  101. small_files = small_expr.evaluate('test_dir')
  102. small_files # => ["test_dir/small2.txt", "test_dir/subdir/small.jpg", "test_dir/small1.txt", "test_dir/small.mp3"]
  103.  
  104. not_mp3_expr = Not.new(FileName.new('*.mp3'))
  105. not_mp3_files = not_mp3_expr.evaluate('test_dir')
  106. not_mp3_files # => ["test_dir/small2.txt", "test_dir/subdir/small.jpg", "test_dir/small1.txt"]
  107.  
  108. class Or < Expression
  109. def initialize(expression1, expression2)
  110. @expression1 = expression1
  111. @expression2 = expression2
  112. end
  113.  
  114. def evaluate(dir)
  115. result1 = @expression1.evaluate(dir)
  116. result2 = @expression2.evaluate(dir)
  117. (result1 + result2).sort.uniq
  118. end
  119. end
  120.  
  121. # MP3ファイルまたは1KBより大きいファイルを一度に検索する
  122.  
  123. big_or_mp3_expr = Or.new(Bigger.new(1024), FileName.new('*.mp3'))
  124. big_or_mp3s = big_or_mp3_expr.evaluate('test_dir')
  125. big_or_mp3s # => ["test_dir/big.mp3", "test_dir/big2.mp3", "test_dir/small.mp3", "test_dir/subdir/other.mp3"]
  126.  
  127. #このような複雑なASTを作ると、別のコンテキストでそれを繰り返し利用できる。
  128. # big_or_mp3_expr.evaluate('test_dir')
  129. # big_or_mp3_expr.evaluate('/home/me/tmp')
  130.  
  131. class And < Expression
  132. def initialize(expression1, expression2)
  133. @expression1 = expression1
  134. @expression2 = expression2
  135. end
  136.  
  137. def evaluate(dir)
  138. result1 = @expression1.evaluate(dir)
  139. result2 = @expression2.evaluate(dir)
  140. (result1 & result2)
  141. end
  142. end
  143.  
  144. ** パーサを使わないインタープリタにすることにした/便利なショートカットを導入(DSL)
  145.  
  146. 上位クラス(Expression) にAnd,Or のシンタックスシュガーを作成して書きやすくする
  147.  
  148. class Expression
  149. def |(other)
  150. Or.new(self, other)
  151. end
  152.  
  153. def &(other)
  154. And.new(self, other)
  155. end
  156. end
  157.  
  158. expr = Or.new(
  159. And.new(Bigger.new(1024), Not.new(Writable.new )),
  160. FileName.new('*.mp3'))
  161. files = expr.evaluate('test_dir')
  162. files # => ["test_dir/big.mp3", "test_dir/big2.mp3", "test_dir/small.mp3", "test_dir/subdir/other.mp3"]
  163.  
  164. expr = (Bigger.new(1024) & Not.new(Writable.new)) | FileName.new('*.mp3') #これは短かくて読みやすい!
  165. files = expr.evaluate('test_dir')
  166. files # => ["test_dir/big.mp3", "test_dir/big2.mp3", "test_dir/small.mp3", "test_dir/subdir/other.mp3"]
Add Comment
Please, Sign In to add comment