filewatch-ext 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []