em-files 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.md +31 -0
  2. data/VERSION +1 -1
  3. data/em-files.gemspec +2 -2
  4. data/lib/em-files.rb +113 -18
  5. metadata +3 -3
data/README.md CHANGED
@@ -26,6 +26,37 @@ methods only, so for special operations use simply:
26
26
  EM::File::open("some_file.txt", "r") do |io|
27
27
  io.native # returns native Ruby File class object
28
28
  end
29
+
30
+ ### Special Uses
31
+
32
+ It's possible to use also another IO objects than `File` object by
33
+ giving appropriate IO instance instead of filename to methods:
34
+
35
+ require "em-files"
36
+ require "stringio"
37
+
38
+ io = StringIO::new
39
+
40
+ EM::run do
41
+ EM::File::open(io) do |io|
42
+ # some multiplexed operations
43
+ end
44
+ end
45
+
46
+ By this way you can also perform for example more time consuming
47
+ operations by simple way (if they can be processed in block manner)
48
+ using filters:
49
+
50
+ require "em-files"
51
+ require "zlib"
52
+
53
+ zip = Zlib::Deflate::new
54
+ filter = Proc::new { |chunk| zip.deflate(chunk, Zlib::SYNC_FLUSH) }
55
+ data = "..." # some bigger than big data
56
+
57
+ EM::run do
58
+ EM::File::write(data, filter) # done in several ticks
59
+ end
29
60
 
30
61
 
31
62
  Contributing
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
data/em-files.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{em-files}
8
- s.version = "0.1.1"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Martin Kozák"]
12
- s.date = %q{2011-03-09}
12
+ s.date = %q{2011-03-19}
13
13
  s.email = %q{martinkozak@martinkozak.net}
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE.txt",
data/lib/em-files.rb CHANGED
@@ -15,6 +15,12 @@ module EM
15
15
  #
16
16
 
17
17
  class File
18
+
19
+ ##
20
+ # Holds the default size of block operated during one tick.
21
+ #
22
+
23
+ RWSIZE = 65536
18
24
 
19
25
  ##
20
26
  # Opens the file.
@@ -31,7 +37,9 @@ module EM
31
37
  # @return [File] file access object
32
38
  #
33
39
 
34
- def self.open(filepath, mode = "r", rwsize = 65536, &block) # 64 kilobytes
40
+ def self.open(filepath, mode = "r", rwsize = self::RWSIZE, &block) # 64 kilobytes
41
+ rwsize = self::RWSIZE if rwsize.nil?
42
+
35
43
  file = self::new(filepath, mode, rwsize)
36
44
  if not block.nil?
37
45
  block.call(file)
@@ -42,38 +50,47 @@ module EM
42
50
 
43
51
  ##
44
52
  # Reads whole content of the file. Be warn, it reads it in
45
- # binary mode.
53
+ # binary mode. If IO object is given instead of filepath, uses
54
+ # it as native one and +mode+ argument is ignored.
46
55
  #
47
56
  # @param [String] filepath path to file
48
57
  # @param [Integer] rwsize size of block operated during one tick
58
+ # @param [Proc] filter filter which for postprocessing each
59
+ # read chunk
49
60
  # @param [Proc] block block for giving back the result
50
61
  #
51
62
 
52
63
 
53
- def self.read(filepath, rwsize = 65536, &block)
64
+ def self.read(filepath, rwsize = self::RWSIZE, filter = nil, &block)
65
+ rwsize = self::RWSIZE if rwsize.nil?
54
66
  self::open(filepath, "rb", rwsize) do |io|
55
- io.read do |out|
56
- block.call(out)
67
+ io.read(nil, filter) do |out|
57
68
  io.close()
69
+ block.call(out)
58
70
  end
59
71
  end
60
72
  end
61
73
 
62
74
  ##
63
- # Writes data to file and closes it. Writes them in binary mode.
75
+ # Writes data to file and closes it. Writes them in binary mode.
76
+ # If IO object is given instead of filepath, uses it as native
77
+ # one and +mode+ argument is ignored.
64
78
  #
65
79
  # @param [String] filepath path to file
66
80
  # @param [String] data data for write
67
81
  # @param [Integer] rwsize size of block operated during one tick
82
+ # @param [Proc] filter filter which for preprocessing each
83
+ # written chunk
68
84
  # @param [Proc] block block called when writing is finished with
69
85
  # written bytes size count as parameter
70
86
  #
71
87
 
72
- def self.write(filepath, data = "", rwsize = 65536, &block)
88
+ def self.write(filepath, data = "", rwsize = self::RWSIZE, filter = nil, &block)
89
+ rwsize = self::RWSIZE if rwsize.nil?
73
90
  self::open(filepath, "wb", rwsize) do |io|
74
- io.write(data) do |length|
75
- block.call(length)
91
+ io.write(data, filter) do |length|
76
92
  io.close()
93
+ block.call(length)
77
94
  end
78
95
  end
79
96
  end
@@ -82,7 +99,7 @@ module EM
82
99
 
83
100
  ##
84
101
  # Holds file object.
85
- # @return [::File]
102
+ # @return [IO]
86
103
  #
87
104
 
88
105
  attr_accessor :native
@@ -97,32 +114,64 @@ module EM
97
114
  @rw_len
98
115
 
99
116
  ##
100
- # Constructor.
117
+ # Holds mode of the object.
118
+ # @return [String]
101
119
  #
102
- # @param [String] filepath path to file
120
+
121
+ attr_reader :mode
122
+ @mode
123
+
124
+ ##
125
+ # Constructor. If IO object is given instead of filepath, uses
126
+ # it as native one and +mode+ argument is ignored.
127
+ #
128
+ # @param [String, IO] filepath path to file or IO object
103
129
  # @param [String] mode file access mode (see equivalent Ruby method)
104
130
  # @param [Integer] rwsize size of block operated during one tick
105
131
  #
106
132
 
107
- def initialize(filepath, mode = "r", rwsize = 65536)
108
- @native = ::File::open(filepath, mode)
133
+ def initialize(filepath, mode = "r", rwsize = self.class::RWSIZE)
134
+ @mode = mode
109
135
  @rw_len = rwsize
136
+
137
+ rwsize = self::RWSIZE if rwsize.nil?
138
+
139
+ # If filepath is directly IO, uses it
140
+ if filepath.kind_of? IO
141
+ @native = filepath
142
+ else
143
+ @native = ::File::open(filepath, mode)
144
+ end
145
+
110
146
  end
111
147
 
112
148
  ##
113
149
  # Reads data from file.
114
150
  #
151
+ # It will reopen the file if +EBADF: Bad file descriptor+ of
152
+ # +File+ class IO object will occur.
153
+ #
115
154
  # @overload read(length, &block)
116
155
  # Reads specified amount of data from file.
117
156
  # @param [Integer] length length for read from file
157
+ # @param [Proc] filter filter which for postprocessing each
158
+ # read chunk
118
159
  # @param [Proc] block callback for returning the result
119
160
  # @overload read(&block)
120
161
  # Reads whole content of file.
162
+ # @param [Proc] filter filter which for processing each block
121
163
  # @param [Proc] block callback for returning the result
122
164
  #
123
165
 
124
- def read(length = nil, &block)
166
+ def read(length = nil, filter = nil, &block)
125
167
  buffer = ""
168
+ pos = 0
169
+
170
+ # Arguments
171
+ if length.kind_of? Proc
172
+ filter = length
173
+ end
174
+
126
175
 
127
176
  worker = Proc::new do
128
177
 
@@ -137,7 +186,23 @@ module EM
137
186
  end
138
187
 
139
188
  # Reads
140
- buffer << @native.read(rlen)
189
+ begin
190
+ chunk = @native.read(rlen)
191
+ if not filter.nil?
192
+ chunk = filter.call(chunk)
193
+ end
194
+ buffer << chunk
195
+ rescue Errno::EBADF
196
+ if @native.kind_of? ::File
197
+ self.reopen!
198
+ @native.seek(pos)
199
+ redo
200
+ else
201
+ raise
202
+ end
203
+ end
204
+
205
+ pos = @native.pos
141
206
 
142
207
  # Returns or continues work
143
208
  if @native.eof? or (buffer.length == length)
@@ -153,22 +218,52 @@ module EM
153
218
  worker.call()
154
219
  end
155
220
 
221
+ ##
222
+ # Reopens the file with the original mode.
223
+ #
224
+
225
+ def reopen!
226
+ @native = ::File.open(@native.path, @mode)
227
+ end
228
+
156
229
  ##
157
230
  # Writes data to file.
158
231
  #
232
+ # It will reopen the file if +EBADF: Bad file descriptor+ of
233
+ # +File+ class IO object will occur.
234
+ #
159
235
  # @param [String] data data for write
236
+ # @param [Proc] filter filter which for preprocessing each
237
+ # written chunk
160
238
  # @param [Proc] block callback called when finish and for giving
161
239
  # back the length of written data
162
240
  #
163
241
 
164
- def write(data, &block)
242
+ def write(data, filter = nil, &block)
165
243
  written = 0
244
+ pos = 0
166
245
 
167
246
  worker = Proc::new do
168
247
 
169
248
  # Writes
170
- written += @native.write(data[written...(written + @rw_len)])
249
+ begin
250
+ chunk = data[written...(written + @rw_len)]
251
+ if not filter.nil?
252
+ chunk = filter.call(chunk)
253
+ end
254
+ written += @native.write(chunk)
255
+ rescue Errno::EBADF
256
+ if @native.kind_of? File
257
+ self.reopen!
258
+ @native.seek(pos)
259
+ redo
260
+ else
261
+ raise
262
+ end
263
+ end
171
264
 
265
+ pos = @native.pos
266
+
172
267
  # Returns or continues work
173
268
  if written >= data.bytesize
174
269
  if not block.nil?
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: em-files
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.1
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - "Martin Koz\xC3\xA1k"
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-09 00:00:00 +01:00
13
+ date: 2011-03-19 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -91,7 +91,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
91
  requirements:
92
92
  - - ">="
93
93
  - !ruby/object:Gem::Version
94
- hash: 50982926357626224
94
+ hash: -3958276784463008069
95
95
  segments:
96
96
  - 0
97
97
  version: "0"