filewatch-ext 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ef395e982a627cd01f74e8fafd896db0c9a7b257
4
+ data.tar.gz: f97e919727137bab3d6f847c63f00426a655aa44
5
+ SHA512:
6
+ metadata.gz: 6e181062f46b83dd8e8a131378f103fe000052923395a590ffd4b5796692505bbfff7427595c56370018a9b26d0c4b592ba2414cdcd1facb55a0a61b4405a0a2
7
+ data.tar.gz: 67c79b025ad906c2669f7ac176a00163705967faf6d03067317cb526bf458880ce1a98d78c79eab67ce8490d8d5713812dc4dac6eb21721acb8eec6b600c45bc
Binary file
@@ -0,0 +1,132 @@
1
+ require "filewatch/ext/tailbase"
2
+ require "filewatch/buftok"
3
+
4
+ module FileWatch::Ext
5
+ class FileTail < FileWatch::Ext::TailBase
6
+
7
+ public
8
+ def subscribe(&block)
9
+ # subscribe(stat_interval = 1, discover_interval = 5, &block)
10
+ @watch.subscribe(@opts[:stat_interval],
11
+ @opts[:discover_interval]) do |event, path|
12
+ case event
13
+ when :create, :create_initial
14
+ if @files.member?(path)
15
+ @logger.debug("#{event} for #{path}: already exists in @files")
16
+ next
17
+ end
18
+ if _open_file(path, event)
19
+ _read_file(path, &block)
20
+ end
21
+ when :modify
22
+ _open_file(path, event) if @opts[:eof_close]
23
+
24
+ if !@files.member?(path)
25
+ @logger.debug(":modify for #{path}, does not exist in @files")
26
+ if _open_file(path, event)
27
+ _read_file(path, &block)
28
+ end
29
+ else
30
+ _read_file(path, &block)
31
+ end
32
+ when :delete
33
+ @logger.debug(":delete for #{path}, deleted from @files")
34
+
35
+ _read_file(path, &block) if !@opts[:eof_close]
36
+ _progressdb_delete(path, &block) if @opts[:progressdb] && @opts[:progressdb_del]
37
+
38
+ @files[path].close if !@opts[:eof_close]
39
+ @files.delete(path)
40
+ @statcache.delete(path)
41
+ else
42
+ @logger.warn("unknown event type #{event} for #{path}")
43
+ end
44
+ end # @watch.subscribe
45
+ end # def each
46
+
47
+ private
48
+ def _open_file(path, event)
49
+ @logger.debug("_open_file: #{path}: opening")
50
+ begin
51
+ if @iswindows && defined? JRUBY_VERSION
52
+ @files[path] = Java::RubyFileExt::getRubyFile(path)
53
+ else
54
+ @files[path] = File.open(path)
55
+ end
56
+ rescue
57
+ # don't emit this message too often. if a file that we can't
58
+ # read is changing a lot, we'll try to open it more often,
59
+ # and might be spammy.
60
+ now = Time.now.to_i
61
+ if now - @lastwarn[path] > OPEN_WARN_INTERVAL
62
+ @logger.warn("failed to open #{path}: #{$!}")
63
+ @lastwarn[path] = now
64
+ else
65
+ @logger.debug("(warn supressed) failed to open #{path}: #{$!}")
66
+ end
67
+ @files.delete(path)
68
+ return false
69
+ end
70
+
71
+ stat = File::Stat.new(path)
72
+
73
+ if @iswindows
74
+ fileId = Winhelper.GetWindowsUniqueFileIdentifier(path)
75
+ inode = [fileId, stat.dev_major, stat.dev_minor]
76
+ else
77
+ inode = [stat.ino.to_s, stat.dev_major, stat.dev_minor]
78
+ end
79
+
80
+ @statcache[path] = inode
81
+ if @sincedb.member?(inode)
82
+ last_size = @sincedb[inode][:pos]
83
+ @logger.debug("#{path}: sincedb last value #{@sincedb[inode]}, cur size #{stat.size}")
84
+ if last_size <= stat.size
85
+ @logger.debug("#{path}: sincedb: seeking to #{last_size}")
86
+ @files[path].sysseek(last_size, IO::SEEK_SET)
87
+ else
88
+ @logger.debug("#{path}: last value size is greater than current value, starting over")
89
+ @sincedb[inode] = {:size => stat.size, :pos => 0}
90
+ end
91
+ elsif (event == :create || event == :create_initial) && @files[path]
92
+ # TODO(sissel): Allow starting at beginning of the file.
93
+ if @opts[:start_new_files_at] == :beginning
94
+ @logger.debug("#{path}: initial create, no sincedb, seeking to beginning of file")
95
+ @files[path].sysseek(0, IO::SEEK_SET)
96
+ @sincedb[inode] = {:size => stat.size, :pos => 0}
97
+ else
98
+ # seek to end
99
+ @logger.debug("#{path}: initial create, no sincedb, seeking to end #{stat.size}")
100
+ @files[path].sysseek(stat.size, IO::SEEK_SET)
101
+ @sincedb[inode] = {:size => stat.size, :pos => stat.size}
102
+ end
103
+ else
104
+ @logger.debug("#{path}: staying at position 0, no sincedb")
105
+ end
106
+
107
+ return true
108
+ end # def _open_file
109
+
110
+ private
111
+ def _read_file(path, &block)
112
+ # BufferedTokenizer is now in codec
113
+ loop do
114
+ begin
115
+ data = @files[path].sysread(32768)
116
+
117
+ yield(path, data, :log)
118
+
119
+ @sincedb[@statcache[path]][:pos] = @files[path].pos
120
+ _check_sincedb(false, path, &block)
121
+ rescue EOFError
122
+ _check_sincedb(true, path, &block)
123
+ _close_file(path) if @opts[:eof_close]
124
+ @logger.debug("End of file reached for #{path}")
125
+ break
126
+ rescue Errno::EWOULDBLOCK, Errno::EINTR
127
+ break
128
+ end
129
+ end
130
+ end # def _read_file
131
+ end # class Tail
132
+ end # module FileWatch
@@ -0,0 +1,179 @@
1
+ require "filewatch/watch"
2
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
3
+ require "filewatch/winhelper"
4
+ end
5
+ require "logger"
6
+ require "rbconfig"
7
+
8
+ include Java if defined? JRUBY_VERSION
9
+ require "JRubyFileExtension.jar" if defined? JRUBY_VERSION
10
+
11
+ module FileWatch::Ext
12
+ class TailBase
13
+ # how often (in seconds) we @logger.warn a failed file open, per path.
14
+ OPEN_WARN_INTERVAL = ENV["FILEWATCH_OPEN_WARN_INTERVAL"] ?
15
+ ENV["FILEWATCH_OPEN_WARN_INTERVAL"].to_i : 300
16
+
17
+ attr_accessor :logger
18
+
19
+ class NoSinceDBPathGiven < StandardError; end
20
+
21
+ public
22
+ def initialize(opts={})
23
+ @iswindows = ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/) != nil)
24
+
25
+ if opts[:logger]
26
+ @logger = opts[:logger]
27
+ else
28
+ @logger = Logger.new(STDERR)
29
+ @logger.level = Logger::INFO
30
+ end
31
+ @files = {}
32
+ @lastwarn = Hash.new { |h, k| h[k] = 0 }
33
+ @watch = FileWatch::Watch.new
34
+ @watch.logger = @logger
35
+ @sincedb = {}
36
+ @sincedb_last_write = 0
37
+ @statcache = {}
38
+ @opts = {
39
+ :sincedb_write_interval => 10,
40
+ :stat_interval => 1,
41
+ :discover_interval => 5,
42
+ :exclude => [],
43
+ :start_new_files_at => :end,
44
+ :progressdb => false,
45
+ :eof_close => false,
46
+ }.merge(opts)
47
+ if !@opts.include?(:sincedb_path)
48
+ @opts[:sincedb_path] = File.join(ENV["HOME"], ".sincedb") if ENV.include?("HOME")
49
+ @opts[:sincedb_path] = ENV["SINCEDB_PATH"] if ENV.include?("SINCEDB_PATH")
50
+ end
51
+ if !@opts.include?(:sincedb_path)
52
+ raise NoSinceDBPathGiven.new("No HOME or SINCEDB_PATH set in environment. I need one of these set so I can keep track of the files I am following.")
53
+ end
54
+ @watch.exclude(@opts[:exclude])
55
+
56
+ _sincedb_open
57
+ end # def initialize
58
+
59
+ public
60
+ def logger=(logger)
61
+ @logger = logger
62
+ @watch.logger = logger
63
+ end # def logger=
64
+
65
+ public
66
+ def tail(path)
67
+ @watch.watch(path)
68
+ end # def tail
69
+
70
+ public
71
+ def subscribe(&block)
72
+ # to be overwritten
73
+ end # def each
74
+
75
+ protected
76
+ def _open_file(path, event)
77
+ # to be overwritten
78
+ end # def _open_file
79
+
80
+ protected
81
+ def _read_file(path, &block)
82
+ # to be overwritten
83
+ end # def _read_file
84
+
85
+ private
86
+ def _close_file(path)
87
+ @files[path].close
88
+ end
89
+
90
+ protected
91
+ def _check_sincedb(eof, path, &block)
92
+ now = Time.now.to_i
93
+ delta = now - @sincedb_last_write
94
+ if eof || delta >= @opts[:sincedb_write_interval]
95
+ @logger.debug("writing sincedb (delta since last write = #{delta})") if @logger.debug?
96
+ _sincedb_write
97
+ _progressdb_write(path, &block) if @opts[:progressdb]
98
+ @sincedb_last_write = now
99
+ end
100
+ end
101
+
102
+ public
103
+ def sincedb_write(reason=nil)
104
+ @logger.debug("caller requested sincedb write (#{reason})")
105
+ _sincedb_write
106
+ end
107
+
108
+ protected
109
+ def _sincedb_open
110
+ path = @opts[:sincedb_path]
111
+ begin
112
+ db = File.open(path)
113
+ rescue
114
+ @logger.debug("_sincedb_open: #{path}: #{$!}")
115
+ return
116
+ end
117
+
118
+ @logger.debug("_sincedb_open: reading from #{path}")
119
+ db.each do |line|
120
+ ino, dev_major, dev_minor, size, pos = line.split(" ", 5)
121
+ inode = [ino, dev_major.to_i, dev_minor.to_i]
122
+ @logger.debug("_sincedb_open: setting #{inode.inspect} to #{pos.to_i}")
123
+ @sincedb[inode] = {:size => size.to_i, :pos => pos.to_i}
124
+ end
125
+ end # def _sincedb_open
126
+
127
+ protected
128
+ def _sincedb_write
129
+ path = @opts[:sincedb_path]
130
+ tmp = "#{path}.new"
131
+ begin
132
+ db = File.open(tmp, "w")
133
+ rescue => e
134
+ @logger.warn("_sincedb_write failed: #{tmp}: #{e}")
135
+ return
136
+ end
137
+
138
+ @sincedb.each do |inode, meta|
139
+ db.puts([inode, meta[:size], meta[:pos]].flatten.join(" "))
140
+ end
141
+ db.close
142
+
143
+ begin
144
+ File.rename(tmp, path)
145
+ rescue => e
146
+ @logger.warn("_sincedb_write rename/sync failed: #{tmp} -> #{path}: #{e}")
147
+ end
148
+ end # def _sincedb_write
149
+
150
+ protected
151
+ def _sincedb_delete(path)
152
+ inode = @statcache[path]
153
+ @sincedb.delete(inode)
154
+ _sincedb_write
155
+ end
156
+
157
+ protected
158
+ def _progressdb_write(path, &block)
159
+ @sincedb.each do |inode, meta|
160
+ line = [inode, meta[:size], meta[:pos]].flatten.join(" ")
161
+ yield(path, line, :progressdb)
162
+ end
163
+ end
164
+
165
+ protected
166
+ def _progressdb_delete(path, &block)
167
+ inode = @statcache[path]
168
+ meta = @sincedb[inode]
169
+
170
+ line = [inode, meta[:size], meta[:pos]].flatten.join(" ")
171
+ yield(path, line, :progressdb_del)
172
+ end
173
+
174
+ public
175
+ def quit
176
+ @watch.quit
177
+ end # def quit
178
+ end # class Tail
179
+ end # module FileWatch
@@ -0,0 +1,149 @@
1
+ require "filewatch/ext/tailbase"
2
+ require "spreadsheet"
3
+
4
+ module FileWatch::Ext
5
+ class XlsTail < FileWatch::Ext::TailBase
6
+
7
+ public
8
+ def initialize(opts={})
9
+ @pos = {}
10
+ super
11
+ end
12
+
13
+ public
14
+ def subscribe(&block)
15
+ # subscribe(stat_interval = 1, discover_interval = 5, &block)
16
+ @watch.subscribe(@opts[:stat_interval],
17
+ @opts[:discover_interval]) do |event, path|
18
+ case event
19
+ when :create, :create_initial
20
+ if @files.member?(path)
21
+ @logger.debug("#{event} for #{path}: already exists in @files")
22
+ next
23
+ end
24
+ if _open_file(path, event)
25
+ _read_file(path, &block)
26
+ end
27
+ when :modify
28
+ @logger.debug(":modify for #{path}")
29
+ when :delete
30
+ @logger.debug(":delete for #{path}, deleted from @files")
31
+
32
+ _progressdb_delete(path, &block) if @opts[:progressdb] && @opts[:progressdb_del]
33
+
34
+ @files.delete(path)
35
+ @statcache.delete(path)
36
+ else
37
+ @logger.warn("unknown event type #{event} for #{path}")
38
+ end
39
+ end # @watch.subscribe
40
+ end # def each
41
+
42
+ private
43
+ def get_size(path)
44
+ workbook = Spreadsheet.open(path)
45
+ pos = 0
46
+ workbook.worksheets.each do |worksheet|
47
+ pos += worksheet.rows.length
48
+ end
49
+ @size = pos
50
+ end
51
+
52
+ private
53
+ def _open_file(path, event)
54
+ @logger.debug("_open_file: #{path}: opening")
55
+ begin
56
+ #Spreadsheet.client_encoding = 'UTF-8'
57
+ @files[path] = Spreadsheet.open(path)
58
+ rescue
59
+ # don't emit this message too often. if a file that we can't
60
+ # read is changing a lot, we'll try to open it more often,
61
+ # and might be spammy.
62
+ now = Time.now.to_i
63
+ if now - @lastwarn[path] > OPEN_WARN_INTERVAL
64
+ @logger.warn("failed to open #{path}: #{$!}")
65
+ @lastwarn[path] = now
66
+ else
67
+ @logger.debug("(warn supressed) failed to open #{path}: #{$!}")
68
+ end
69
+ #@files.delete(path)
70
+ return false
71
+ end
72
+
73
+ stat = File::Stat.new(path)
74
+ size = get_size(path)
75
+
76
+ if @iswindows
77
+ fileId = Winhelper.GetWindowsUniqueFileIdentifier(path)
78
+ inode = [fileId, stat.dev_major, stat.dev_minor]
79
+ else
80
+ inode = [stat.ino.to_s, stat.dev_major, stat.dev_minor]
81
+ end
82
+
83
+ @statcache[path] = inode
84
+
85
+ if @sincedb.member?(inode)
86
+ last_size = @sincedb[inode][:pos]
87
+ @logger.debug("#{path}: sincedb last value #{@sincedb[inode]}, cur size #{size}")
88
+ if last_size <= size
89
+ @logger.debug("#{path}: sincedb: seeking to #{last_size}")
90
+ @pos[path] = last_size
91
+ else
92
+ @logger.debug("#{path}: last value size is greater than current value, starting over")
93
+ @sincedb[inode] = {:size => size, :pos => 0}
94
+ end
95
+ elsif event == :create_initial && @files[path]
96
+ # TODO(sissel): Allow starting at beginning of the file.
97
+ if @opts[:start_new_files_at] == :beginning
98
+ @logger.debug("#{path}: initial create, no sincedb, seeking to beginning of file")
99
+ @pos[path] = 0
100
+ @sincedb[inode] = {:size => size, :pos => 0}
101
+ else
102
+ # seek to end
103
+ @logger.debug("#{path}: initial create, no sincedb, seeking to end #{size}")
104
+ @pos[path] = size
105
+ @sincedb[inode] = {:size => size, :pos => size}
106
+ end
107
+ else
108
+ @logger.debug("#{path}: staying at position 0, no sincedb")
109
+ end
110
+
111
+ return true
112
+ end # def _open_file
113
+
114
+ private
115
+ def _read_file(path, &block)
116
+ changed = false
117
+ pos = 0
118
+
119
+ worksheets = @files[path].worksheets
120
+
121
+ worksheets.each_with_index do |worksheet, index_sheet|
122
+
123
+ worksheet.each_with_index do |row, index_row|
124
+ pos += 1
125
+
126
+ if pos > @pos[path]
127
+ changed = true
128
+
129
+ sheet_name = worksheet.name.empty? ? "Sheet#{index_sheet+1}" : worksheet.name
130
+
131
+ if pos == @size #end of file is reached
132
+ data = {:row => row, :wsname => sheet_name, :eof => true}
133
+ else
134
+ data = {:row => row, :wsname => sheet_name, :eof => false}
135
+ end
136
+
137
+ yield(path, data, :log)
138
+
139
+ @pos[path] = pos
140
+ @sincedb[@statcache[path]][:pos] = pos
141
+ _check_sincedb(false, path, &block)
142
+ end
143
+ end
144
+ end
145
+ _check_sincedb(true, path, &block) if changed
146
+ end # def _read_file
147
+
148
+ end # class Tail
149
+ end # module FileWatch
@@ -0,0 +1,147 @@
1
+ require "filewatch/ext/tailbase"
2
+ require "simple_xlsx_reader"
3
+
4
+ module FileWatch::Ext
5
+ class XlsxTail < FileWatch::Ext::TailBase
6
+
7
+ public
8
+ def initialize(opts={})
9
+ @pos = {}
10
+ super
11
+ end
12
+
13
+ public
14
+ def subscribe(&block)
15
+ # subscribe(stat_interval = 1, discover_interval = 5, &block)
16
+ @watch.subscribe(@opts[:stat_interval],
17
+ @opts[:discover_interval]) do |event, path|
18
+ case event
19
+ when :create, :create_initial
20
+ if @files.member?(path)
21
+ @logger.debug("#{event} for #{path}: already exists in @files")
22
+ next
23
+ end
24
+ if _open_file(path, event)
25
+ _read_file(path, &block)
26
+ end
27
+ when :modify
28
+ @logger.debug(":modify for #{path}")
29
+ when :delete
30
+ @logger.debug(":delete for #{path}, deleted from @files")
31
+
32
+ _progressdb_delete(path, &block) if @opts[:progressdb] && @opts[:progressdb_del]
33
+
34
+ @files.delete(path)
35
+ @statcache.delete(path)
36
+ else
37
+ @logger.warn("unknown event type #{event} for #{path}")
38
+ end
39
+ end # @watch.subscribe
40
+ end # def each
41
+
42
+ private
43
+ def get_size(path)
44
+ doc = SimpleXlsxReader.open(path)
45
+ pos = 0
46
+ doc.sheets.each do |worksheet|
47
+ pos += worksheet.rows.length
48
+ end
49
+ @size = pos
50
+ end
51
+
52
+ private
53
+ def _open_file(path, event)
54
+ @logger.debug("_open_file: #{path}: opening")
55
+ begin
56
+ @files[path] = SimpleXlsxReader.open(path)
57
+ rescue
58
+ # don't emit this message too often. if a file that we can't
59
+ # read is changing a lot, we'll try to open it more often,
60
+ # and might be spammy.
61
+ now = Time.now.to_i
62
+ if now - @lastwarn[path] > OPEN_WARN_INTERVAL
63
+ @logger.warn("failed to open #{path}: #{$!}")
64
+ @lastwarn[path] = now
65
+ else
66
+ @logger.debug("(warn supressed) failed to open #{path}: #{$!}")
67
+ end
68
+ #@files.delete(path)
69
+ return false
70
+ end
71
+
72
+ stat = File::Stat.new(path)
73
+ size = get_size(path)
74
+
75
+ if @iswindows
76
+ fileId = Winhelper.GetWindowsUniqueFileIdentifier(path)
77
+ inode = [fileId, stat.dev_major, stat.dev_minor]
78
+ else
79
+ inode = [stat.ino.to_s, stat.dev_major, stat.dev_minor]
80
+ end
81
+
82
+ @statcache[path] = inode
83
+
84
+ if @sincedb.member?(inode)
85
+ last_size = @sincedb[inode][:pos]
86
+ @logger.debug("#{path}: sincedb last value #{@sincedb[inode]}, cur size #{size}")
87
+ if last_size <= size
88
+ @logger.debug("#{path}: sincedb: seeking to #{last_size}")
89
+ @pos[path] = last_size
90
+ else
91
+ @logger.debug("#{path}: last value size is greater than current value, starting over")
92
+ @sincedb[inode] = {:size => size, :pos => 0}
93
+ end
94
+ elsif event == :create_initial && @files[path]
95
+ # TODO(sissel): Allow starting at beginning of the file.
96
+ if @opts[:start_new_files_at] == :beginning
97
+ @logger.debug("#{path}: initial create, no sincedb, seeking to beginning of file")
98
+ @pos[path] = 0
99
+ @sincedb[inode] = {:size => size, :pos => 0}
100
+ else
101
+ # seek to end
102
+ @logger.debug("#{path}: initial create, no sincedb, seeking to end #{size}")
103
+ @pos[path] = size
104
+ @sincedb[inode] = {:size => size, :pos => size}
105
+ end
106
+ else
107
+ @logger.debug("#{path}: staying at position 0, no sincedb")
108
+ end
109
+
110
+ return true
111
+ end # def _open_file
112
+
113
+ private
114
+ def _read_file(path, &block)
115
+ changed = false
116
+ pos = 0
117
+
118
+ worksheets = @files[path].sheets
119
+
120
+ worksheets.each_with_index do |worksheet, index_sheet|
121
+
122
+ worksheet.rows.each_with_index do |row, index_row|
123
+ pos += 1
124
+
125
+ if pos > @pos[path]
126
+ changed = true
127
+ sheet_name = worksheet.name.empty? ? "Sheet#{index_sheet+1}" : worksheet.name
128
+
129
+ if pos == @size #end of file is reached
130
+ data = {:row => row, :wsname => sheet_name, :eof => true}
131
+ else
132
+ data = {:row => row, :wsname => sheet_name, :eof => false}
133
+ end
134
+
135
+ yield(path, data, :log)
136
+
137
+ @pos[path] = pos
138
+ @sincedb[@statcache[path]][:pos] = pos
139
+ _check_sincedb(false, path, &block)
140
+ end
141
+ end
142
+ end
143
+ _check_sincedb(true, path, &block) if changed
144
+ end # def _read_file
145
+
146
+ end # class Tail
147
+ end # module FileWatch
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: filewatch-ext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dietmar Duft
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: filewatch
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.1
20
+ requirement: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 0.5.1
25
+ prerelease: false
26
+ type: :runtime
27
+ - !ruby/object:Gem::Dependency
28
+ name: simple_xlsx_reader
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.8
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: 0.9.8
39
+ prerelease: false
40
+ type: :runtime
41
+ - !ruby/object:Gem::Dependency
42
+ name: axlsx
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 2.0.1
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ~>
51
+ - !ruby/object:Gem::Version
52
+ version: 2.0.1
53
+ prerelease: false
54
+ type: :runtime
55
+ - !ruby/object:Gem::Dependency
56
+ name: spreadsheet
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.7
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 0.9.7
67
+ prerelease: false
68
+ type: :runtime
69
+ description: Extensions for ruby-filewatcher, like xls, xlsx
70
+ email:
71
+ - dietmar@signifydata.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/JRubyFileExtension.jar
77
+ - lib/filewatch/ext/tailbase.rb
78
+ - lib/filewatch/ext/filetail.rb
79
+ - lib/filewatch/ext/xlsxtail.rb
80
+ - lib/filewatch/ext/xlstail.rb
81
+ homepage: https://bitbucket.org/signify/ruby-filewatch-ext
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.1.9
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: filewatch extensions
106
+ test_files: []