win32-dirmonitor 1.0.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: 50e164eadb4120514620c9163557cd77668cebe5
4
+ data.tar.gz: 022e4a74724f9bd61066091b311585124ac4a043
5
+ SHA512:
6
+ metadata.gz: eac0b85c2ba9bdfb1f963c8f2238421346590e708507cccf1197b9f8f171115bde6f228e2653118dc16e017de726ab2364acc70e159380dff1a6582f47c63814
7
+ data.tar.gz: 8209e7917136b19b92ee66195a4184a142dcaf5aed18503c2f3bd88b591cc8e4d0e636db3fc35e441013f800ddc19dd2cc38e39f9c282d111acdba3c29c4ea74
data/CHANGES ADDED
@@ -0,0 +1,3 @@
1
+ == 1.0.0 - 22-Jan-2014
2
+ * Initial release.
3
+ * This library replaces win32-changejournal.
data/MANIFEST ADDED
@@ -0,0 +1,8 @@
1
+ * CHANGES
2
+ * README
3
+ * MANIFEST
4
+ * Rakefile
5
+ * win32-dirmonitor.gemspec
6
+ * lib/win32/dirmonitor.rb
7
+ * examples/example_dirmonitor.rb
8
+ * test/test_win32_dirmonitor.rb
data/README ADDED
@@ -0,0 +1,52 @@
1
+ == Description
2
+ A class for monitoring directories on MS Windows.
3
+
4
+ == Installation
5
+ gem install win32-dirmonitor
6
+
7
+ == Synopsis
8
+ require 'win32/dirmonitor'
9
+ include Win32
10
+
11
+ # Wait for a change in your home directory and report any changes.
12
+
13
+ monitor = Win32::DirMonitor.new(ENV['HOME'])
14
+
15
+ # Wait up to 5 minutes for a change.
16
+ monitor.wait(300){ |struct|
17
+ puts 'Something changed'
18
+ puts 'File: ' + struct.file
19
+ puts 'Action: ' + struct.action
20
+ struct.changes.each do |change|
21
+ puts "Change: " + change[0].to_s
22
+ puts "Old: " + change[1].to_s
23
+ puts "New: " + change[2].to_s
24
+ end
25
+ }
26
+
27
+ == Notes
28
+ This replaces the win32-changejournal library and supplants the
29
+ win32-changenotify library since it gives details about the changes
30
+ that occur.
31
+
32
+ == Future Plans
33
+ Allow files in subdirectories to be monitored as well.
34
+
35
+ == Known Bugs
36
+ None that I know of. Please log any bug reports on the RubyForge
37
+ project page at https://github.com/djberg96/win32-dirmonitor.
38
+
39
+ == License
40
+ Artistic 2.0
41
+
42
+ == Copyright
43
+ (C) 2014 Daniel J. Berger, All Rights Reserved
44
+
45
+ == Warranty
46
+ This library is provided "as is" and without any express or
47
+ implied warranties, including, without limitation, the implied
48
+ warranties of merchantability and fitness for a particular purpose.
49
+
50
+ == Authors
51
+ * Daniel J. Berger
52
+ * Park Heesob
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+
5
+ CLEAN.include("**/*.gem", "**/*.rbc", "**/*.rbx")
6
+
7
+ namespace :gem do
8
+ desc "Create the win32-dirmonitor gem"
9
+ task :create => [:clean] do
10
+ spec = eval(IO.read('win32-dirmonitor.gemspec'))
11
+ if Gem::VERSION < "2.0"
12
+ Gem::Builder.new(spec).build
13
+ else
14
+ require 'rubygems/package'
15
+ Gem::Package.build(spec)
16
+ end
17
+ end
18
+
19
+ desc "Install the win32-clipboard library"
20
+ task :install => [:create] do
21
+ file = Dir["*.gem"].first
22
+ sh "gem install #{file}"
23
+ end
24
+ end
25
+
26
+ desc 'Run the example program'
27
+ task :example do |t|
28
+ ruby '-Ilib examples/example_dirmonitor.rb'
29
+ end
30
+
31
+ Rake::TestTask.new(:test) do |t|
32
+ t.warning = true
33
+ t.verbose = true
34
+ end
35
+
36
+ task :default => :test
@@ -0,0 +1,23 @@
1
+ ########################################################################
2
+ # example_changejournal.rb
3
+ #
4
+ # A test script for general futzing. Modify as you see fit. You can
5
+ # run this test script via the 'rake example' task.
6
+ ########################################################################
7
+ require 'win32/dirmonitor'
8
+
9
+ puts 'VERSION: ' + Win32::DirMonitor::VERSION
10
+
11
+ monitor = Win32::DirMonitor.new(ENV['HOME'])
12
+
13
+ # Wait up to 5 minutes for a change journals
14
+ monitor.wait(300){ |struct|
15
+ puts 'Something changed'
16
+ puts 'File: ' + struct.file
17
+ puts 'Action: ' + struct.action
18
+ struct.changes.each do |change|
19
+ puts "Change: " + change[0].to_s
20
+ puts "Old: " + change[1].to_s
21
+ puts "New: " + change[2].to_s
22
+ end
23
+ }
@@ -0,0 +1,146 @@
1
+ require 'socket'
2
+ require 'win32ole'
3
+ require 'timeout'
4
+
5
+ module Win32
6
+ class DirMonitor
7
+ class Error < StandardError; end
8
+
9
+ # The version of the win32-dirmonitor library
10
+ VERSION = '1.0.0'
11
+
12
+ # The struct yielded to the wait method
13
+ DirMonitorStruct = Struct.new(
14
+ 'DirMonitorStruct',
15
+ :file,
16
+ :action,
17
+ :changes
18
+ )
19
+
20
+ # The path to be monitored.
21
+ attr_reader :path
22
+
23
+ # The host on which to monitor the path.
24
+ attr_reader :host
25
+
26
+ # Creates a new DirMonitor object which sets the path and hostname
27
+ # on which the filesystem will be monitored for changes. If no hostname
28
+ # is provided, then the current host is assumed.
29
+ #
30
+ def initialize(path, host = Socket.gethostname)
31
+ raise ArgumentError unless File.exists?(path)
32
+ raise TypeError unless path.is_a?(String)
33
+ raise TypeError unless host.is_a?(String)
34
+
35
+ @path = path.tr("/", "\\")
36
+ @host = host
37
+ @conn = "winmgmts:{impersonationlevel=impersonate}!//#{host}/root/cimv2"
38
+ end
39
+
40
+ # A event loop that will yield a DirMonitorStruct object whenever there
41
+ # is a change in a file on the path set in the constructor. The loop will
42
+ # timeout after the number of seconds provided, or indefinitely if no
43
+ # argument is provided.
44
+ #
45
+ # The DirMonitorStruct contains the following members:
46
+ #
47
+ # * file # The full path of the file that was changed.
48
+ # * action # Either create, delete or modify.
49
+ # * changes # If modified, includes an array of changes.
50
+ #
51
+ # If a modification occurs, the 'changes' struct member contains an
52
+ # array of arrays that describes the change. Each sub-array contains
53
+ # three members - the item that was modified, the previous value, and
54
+ # the current value.
55
+ #
56
+ # Example:
57
+ #
58
+ # mon = Win32::DirMonitor.new("C:/Users/foo")
59
+ #
60
+ # # Monitor filesystem for one minute.
61
+ # mon.wait(60){ |s| p s }
62
+ #
63
+ # # Sample struct returned after file was marked
64
+ # # hidden and read-only:
65
+ #
66
+ # #<struct Struct::DirMonitorStruct
67
+ # file="c:\\Users\\foo\\test.txt",
68
+ # action="modify",
69
+ # changes=[
70
+ # ["AccessMask", "2032127", "2032057"],
71
+ # ["Hidden", "false", "true"],
72
+ # ["Writeable", "true", "false"]
73
+ # ]
74
+ # >
75
+ #
76
+ def wait(seconds = nil)
77
+ raise TypeError unless seconds.is_a?(Numeric) if seconds
78
+
79
+ ole = WIN32OLE.connect(@conn)
80
+ drive = @path.split(':').first + ":"
81
+ folder = @path.split(':').last.gsub("\\", "\\\\\\\\")
82
+ folder << "\\\\" unless folder[-1] == "\\"
83
+
84
+ query = %Q{
85
+ select * from __instanceOperationEvent
86
+ within 2
87
+ where targetInstance isa 'CIM_DataFile'
88
+ and targetInstance.Drive='#{drive}'
89
+ and targetInstance.Path='#{folder}'
90
+ }
91
+
92
+ # Asynchronous call. This will let the user break out of it manually.
93
+ sink = WIN32OLE.new('WbemScripting.SWbemSink')
94
+ event = WIN32OLE_EVENT.new(sink)
95
+
96
+ ole.execNotificationQueryAsync(sink, query)
97
+ sleep 0.5
98
+
99
+ event.on_event("OnObjectReady"){ |object, context|
100
+ target = object.TargetInstance
101
+ struct = DirMonitorStruct.new
102
+ struct[:file] = target.Name
103
+
104
+ case object.Path_.Class.to_s
105
+ when "__InstanceCreationEvent"
106
+ struct[:action] = 'create'
107
+ when "__InstanceDeletionEvent"
108
+ struct[:action] = 'delete'
109
+ when "__InstanceModificationEvent"
110
+ previous = object.PreviousInstance
111
+ struct[:action] = 'modify'
112
+ struct[:changes] = []
113
+
114
+ target.Properties_.each{ |prop|
115
+ if prop.Value != previous.send(prop.Name)
116
+ struct[:changes] << [
117
+ prop.Name,
118
+ previous.send(prop.Name).to_s,
119
+ prop.Value.to_s
120
+ ]
121
+ end
122
+ }
123
+ end
124
+
125
+ yield struct
126
+ }
127
+
128
+ # If an argument is provided, timeout after that many seconds.
129
+ if seconds
130
+ begin
131
+ Timeout.timeout(seconds){
132
+ loop do
133
+ WIN32OLE_EVENT.message_loop
134
+ end
135
+ }
136
+ rescue Timeout::Error
137
+ # Do nothing, return control to user
138
+ end
139
+ else
140
+ loop do
141
+ WIN32OLE_EVENT.message_loop
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,103 @@
1
+ #############################################################################
2
+ # test_win32_dirmonitor.rb
3
+ #
4
+ # Test suite for the win32-dirmonitor library. You should run this
5
+ # via the 'rake test' task.
6
+ #############################################################################
7
+ require 'test-unit'
8
+ require 'win32/dirmonitor'
9
+ include Win32
10
+
11
+ class TC_Win32_DirMonitor < Test::Unit::TestCase
12
+ def self.startup
13
+ Dir.chdir(File.expand_path(File.dirname(__FILE__)))
14
+ @@file = 'win32_dirmonitor_test.txt'
15
+ end
16
+
17
+ def setup
18
+ # The thread is used to force an event to happen for the tests
19
+ @monitor = DirMonitor.new(Dir.pwd)
20
+ @thread = Thread.new{
21
+ sleep 2
22
+ File.open(@@file, 'w'){ |fh| fh.puts 'Delete me!' }
23
+ }
24
+ end
25
+
26
+ test "version constant is set to expected value" do
27
+ assert_equal('1.0.0', DirMonitor::VERSION)
28
+ end
29
+
30
+ test "constructor requires a path argument" do
31
+ assert_raise(ArgumentError){ DirMonitor.new }
32
+ end
33
+
34
+ test "path and host arguments must be strings" do
35
+ assert_raise(TypeError){ DirMonitor.new(1) }
36
+ assert_raise(TypeError){ DirMonitor.new(Dir.pwd, 1) }
37
+ end
38
+
39
+ test "path argument must exist" do
40
+ assert_raise(ArgumentError){ DirMonitor.new("C:/Bogus/Bogus") }
41
+ end
42
+
43
+ test "wait method yields a frozen DirMonitorStruct" do
44
+ @thread.join
45
+ @monitor.wait(2){ |s|
46
+ assert_kind_of(Struct::DirMonitorStruct, s)
47
+ assert_equal(['action', 'file', 'changes'], s.members)
48
+ assert_kind_of(Array, s.changes)
49
+ assert_kind_of(Array, s.changes.first)
50
+ assert_true(s.frozen?)
51
+ }
52
+ end
53
+
54
+ test "wait method basic functionality" do
55
+ assert_respond_to(@monitor, :wait)
56
+ end
57
+
58
+ # We provide some very short timeouts here - shouldn't slow the tests down
59
+ test "wait method accepts an optional timeout value" do
60
+ assert_nothing_raised{ @monitor.wait(0.01){ |s| } }
61
+ end
62
+
63
+ test "wait method accepts a single integer argument only" do
64
+ assert_raise(ArgumentError){ @monitor.wait(1,1) }
65
+ assert_raise(TypeError){ @monitor.wait('a') }
66
+ end
67
+
68
+ test "a custom error class is defined" do
69
+ assert_kind_of(Object, Win32::DirMonitor::Error)
70
+ end
71
+
72
+ test "path attribute basic functionality" do
73
+ assert_respond_to(@monitor, :path)
74
+ assert_nothing_raised{ @monitor.path }
75
+ assert_kind_of(String, @monitor.path)
76
+ end
77
+
78
+ test "path method returns expected value" do
79
+ assert_equal(Dir.pwd, @monitor.path.tr("\\", "/"))
80
+ end
81
+
82
+ test "host attribute basic functionality" do
83
+ assert_respond_to(@monitor, :host)
84
+ assert_nothing_raised{ @monitor.host}
85
+ assert_kind_of(String, @monitor.host)
86
+ end
87
+
88
+ test "host method returns expected value" do
89
+ assert_equal(Socket.gethostname, @monitor.host)
90
+ end
91
+
92
+ def teardown
93
+ @thread.kill if @thread.alive?
94
+
95
+ @monitor = nil
96
+ @flags = nil
97
+ @thread = nil
98
+ end
99
+
100
+ def self.shutdown
101
+ File.delete(@@file) if File.exists?(@@file)
102
+ end
103
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'win32-dirmonitor'
5
+ spec.version = '1.0.0'
6
+ spec.authors = ['Daniel J. Berger', 'Park Heesob']
7
+ spec.license = 'Artistic 2.0'
8
+ spec.email = 'djberg96@gmail.com'
9
+ spec.homepage = 'https://github.com/djberg96/win32-dirmonitor'
10
+ spec.summary = 'A library for monitoring files on MS Windows'
11
+ spec.test_file = 'test/test_win32_dirmonitor.rb'
12
+ spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
13
+
14
+ spec.rubyforge_project = 'win32utils'
15
+
16
+ spec.extra_rdoc_files = [
17
+ 'README',
18
+ 'CHANGES',
19
+ 'MANIFEST',
20
+ ]
21
+
22
+ spec.add_development_dependency('test-unit')
23
+ spec.add_development_dependency('rake')
24
+
25
+ spec.description = <<-EOF
26
+ The win32-dirmonitor library provides a way to asynchronously monitor
27
+ changes to files in a given directory, and provides detailed information
28
+ about the changes that occurred.
29
+ EOF
30
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: win32-dirmonitor
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel J. Berger
8
+ - Park Heesob
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-01-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: test-unit
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ description: |2
43
+ The win32-dirmonitor library provides a way to asynchronously monitor
44
+ changes to files in a given directory, and provides detailed information
45
+ about the changes that occurred.
46
+ email: djberg96@gmail.com
47
+ executables: []
48
+ extensions: []
49
+ extra_rdoc_files:
50
+ - README
51
+ - CHANGES
52
+ - MANIFEST
53
+ files:
54
+ - CHANGES
55
+ - examples/example_dirmonitor.rb
56
+ - lib/win32/dirmonitor.rb
57
+ - MANIFEST
58
+ - Rakefile
59
+ - README
60
+ - test/test_win32_dirmonitor.rb
61
+ - win32-dirmonitor.gemspec
62
+ homepage: https://github.com/djberg96/win32-dirmonitor
63
+ licenses:
64
+ - Artistic 2.0
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project: win32utils
82
+ rubygems_version: 2.0.3
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: A library for monitoring files on MS Windows
86
+ test_files:
87
+ - test/test_win32_dirmonitor.rb