Class: Dir

Inherits:
Object show all
Defined in:
lib/ruby_archive/patch/dir.rb

Constant Summary collapse

@@ruby_archive_dir_class_bind =
binding

Class Method Summary collapse

Class Method Details

.[](*glob) ⇒ Object



177
# File 'lib/ruby_archive/patch/dir.rb', line 177

def [](*glob); return Dir.glob(glob,0); end

.forward_method_array(method, min_arguments = 1, array_index = 0) ⇒ Object

See forward_method_single. Does nearly the same thing, but assumes the argument list ends with a list of files to operate on rather than a single file to operate on.

This code is basically File.forward_method_multi adapted for Dir.glob and the like



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/ruby_archive/patch/dir.rb', line 73

def forward_method_array method, min_arguments=1, array_index=0
  alias_name = "ruby_archive_original_#{method}".intern
  eval_line = __LINE__; eval %{
    unless Dir.respond_to?(:#{alias_name})
      alias_method(:#{alias_name}, :#{method})
    end
    protected(:#{alias_name})

    define_method(:#{method}) do |*args|
      if (#{min_arguments} > 0 && args.size == 0)
        raise ArgumentError, "wrong number of arguments (0 for #{min_arguments})"
      end

      # grab args before the list of filepaths, and the list of filepaths
      args_before_array = nil
      if #{array_index} == 0
        args_before_array = []
      else
        args_before_array = args[0..#{array_index - 1}]
      end
      args_after_array = args[#{array_index + 1}..(args.size - 1)]

      path_list = args[#{array_index}]

      path_list = [path_list] unless path_list.is_a?(Array)

      results = []
      path_list.each do |path|
        location_info = File.in_archive?(path)
        if location_info == false
          args_to_send = args_before_array + [path] + args_after_array
          results += Dir.send(:#{alias_name},*args_to_send)
          next
        else
          begin
            dir_handler = RubyArchive.get(location_info[0]).dir
            raise NotImplementedError unless dir_handler.respond_to?(:#{method})
            args_to_send = args_before_array + [location_info[1]] + args_after_array
            get_array = dir_handler.send(:#{method},*args_to_send)
            results += get_array.map { |file| "\#{location_info[0]}!\#{file}" }
            next
          rescue NotImplementedError
            raise NotImplementedError, "#{method} not implemented in handler for specified archive"
          end
        end
      end
      return results
    end
  }, @@ruby_archive_dir_class_bind, __FILE__, eval_line
end

.forward_method_single(method, min_arguments = 1, path_arg_index = 0, on_load_error = nil) ⇒ Object

Automates creating class methods that operate on either normal files or files within archives, given a symbol with the name of the method and the index of the argument containing the file name.

It performs tasks in the following order:

  • alias the original method to ruby_archive_original_name, marks the alias as protected.

  • overrides the class method so that it tries, in order:

    1. returns the result of the original class method if the given file exists
    2. returns the result of the original class method if an archive is not specified
    3. returns the result of the archive handler method if an archive is specified
    

The current method of doing this is kind of ugly and involves ‘eval’, but it works(tm). This method is definitely a candidate for improvement.

This code is heavily duplicated from File.forward_method_single - I would like to make the same code work in two different places but couldn’t quickly find a way.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/ruby_archive/patch/dir.rb', line 23

def forward_method_single method, min_arguments=1, path_arg_index=0, on_load_error=nil
  alias_name = "ruby_archive_original_#{method}".intern
  eval_line = __LINE__; eval %{
    unless Dir.respond_to?(:#{alias_name})
      alias_method(:#{alias_name}, :#{method})
    end
    protected(:#{alias_name})

    define_method(:#{method}) do |*args|
      if (#{min_arguments} > 0 && args.size == 0)
        raise ArgumentError, "wrong number of arguments (0 for #{min_arguments})"
      end

      # grab args before and after the filepath
      args_before_path = nil
      if #{path_arg_index} == 0
        args_before_path = []
      else
        args_before_path = args[0..(#{path_arg_index - 1})]
      end
      path = args[#{path_arg_index}]
      args_after_path = args[(#{path_arg_index + 1})..(args.size-1)]
    
      # get file location info and forward it to the appropriate method
      location_info = File.in_archive?(path)
      if location_info == false
        return Dir.send(:#{alias_name},*args)
      else
        begin
          dir_handler = RubyArchive.get(location_info[0]).dir
          raise NotImplementedError unless dir_handler.respond_to?(:#{method})
          args_to_send = args_before_path + [location_info[1]] + args_after_path
          return dir_handler.send(:#{method},*args_to_send)
        rescue LoadError
          raise if #{on_load_error.inspect}.nil?
          return #{on_load_error.inspect}
        rescue NotImplementedError
          raise NotImplementedError, "#{method} not implemented in handler for specified archive"
        end
      end
    end
  }, @@ruby_archive_dir_class_bind, __FILE__, eval_line
end

.forward_method_unsupported(method, min_arguments = 1, path_args = [0], return_instead = :raise) ⇒ Object

Marks a function as unsupported by archives. path_args should be an array of argument indices containing filepaths to check.

This code is heavily duplicated from File.forward_method_unsupported - I would like to make the same code work in two different places but couldn’t quickly find a way.



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/ruby_archive/patch/dir.rb', line 131

def forward_method_unsupported method, min_arguments=1, path_args=[0], return_instead=:raise
  alias_name = "ruby_archive_original_#{method}".intern
  eval_line = __LINE__; eval %{
    unless Dir.respond_to?(:#{alias_name})
      alias_method(:#{alias_name}, :#{method})
    end
    protected(:#{alias_name})

    define_method(:#{method}) do |*args|
      if (#{min_arguments} > 0 && args.size == 0)
        raise ArgumentError, "wrong number of arguments (0 for #{min_arguments})"
      end

      # grab args before the list of filepaths, and the list of filepaths
      #{path_args.inspect}.each do |i|
        if File.in_archive?(args[i]) != false
          unless #{return_instead.inspect} == :raise
            warn "Dir.#{method} is not supported for files within archives"
            puts "#{return_instead.inspect}"
            return #{return_instead.inspect}
          end
          raise NotImplementedError, "Dir.#{method} is not supported for files within archives (yet)"
        end
      end
      
      Dir.send(:#{alias_name},*args)
    end
  }, @@ruby_archive_dir_class_bind, __FILE__, eval_line
end