zeus-edge 0.12.1

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.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zeus.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Burke Libbey
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'fileutils'
4
+ require 'pathname'
5
+
6
+ ROOT_PATH = Pathname.new(File.expand_path("../../", __FILE__))
7
+ RUBYGEM_PATH = Pathname.new(File.expand_path("../", __FILE__))
8
+
9
+ task build: [:import_externals, :version, :manifest]
10
+ task default: :build
11
+
12
+ task :import_externals do
13
+ puts "building rubygem"
14
+
15
+ Rake::Task[:clean].invoke
16
+
17
+ FileUtils.rm_r(RUBYGEM_PATH + "man") rescue nil
18
+ FileUtils.rm_r(RUBYGEM_PATH + "build") rescue nil
19
+
20
+ # manpages
21
+ FileUtils.mkdir(RUBYGEM_PATH + "man")
22
+ FileUtils.cp_r(ROOT_PATH + "man/build", RUBYGEM_PATH + "man")
23
+
24
+ # multi-arch binaries
25
+ FileUtils.cp_r(ROOT_PATH + "build", RUBYGEM_PATH + "build")
26
+
27
+ Rake::Task[:manifest].invoke
28
+ Rake::Task[:build].invoke
29
+ end
30
+
31
+ task :version do
32
+ version = File.read('../VERSION').chomp
33
+ File.open('lib/zeus/version.rb', 'w') { |f| f.puts <<END
34
+ module Zeus
35
+ VERSION = "#{version}"
36
+ end
37
+ END
38
+ }
39
+ end
40
+
41
+ task :manifest do
42
+ files = `find . -type f | sed 's|^\./||'`.lines.map(&:chomp)
43
+ exceptions = [
44
+ /.gitignore$/,
45
+ /^MANIFEST$/,
46
+ /^pkg\//,
47
+ ]
48
+ files.reject! { |f| exceptions.any? {|ex| f =~ ex }}
49
+ File.open('MANIFEST', 'w') {|f| f.puts files.join("\n") }
50
+ end
51
+
52
+ task :clean do
53
+ FileUtils.rm(RUBYGEM_PATH + "lib/zeus/version.rb") rescue nil
54
+ FileUtils.rm_r(RUBYGEM_PATH + "man") rescue nil
55
+ FileUtils.rm_r(RUBYGEM_PATH + "build") rescue nil
56
+ end
57
+
data/bin/zeus ADDED
@@ -0,0 +1,16 @@
1
+ platform = `uname -sm`
2
+
3
+ exe = case platform
4
+ when /^Darwin/ ; "zeus-darwin-amd64"
5
+ when /^Linux.*64/ ; "zeus-linux-amd64"
6
+ when /^Linux.*/ ; "zeus-linux-386"
7
+ else
8
+ puts "Zeus is not supported on your platform."
9
+ puts "It's not likely to ever be possible on Windows."
10
+ puts "If you're using another platform that you think should work easily, open an issue at:"
11
+ puts "https://github.com/burke/zeus/issues"
12
+ exit 1
13
+ end
14
+
15
+ zeusgemdir = File.expand_path("../../", __FILE__)
16
+ exec "#{zeusgemdir}/build/#{exe}", *ARGV
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,24 @@
1
+ if /linux/ =~ RUBY_PLATFORM
2
+ open("Makefile", "wb") do |f|
3
+ f.write <<-EOF
4
+ CXX = g++
5
+ CXXFLAGS = -O3 -g -Wall
6
+
7
+ inotify-wrapper: inotify-wrapper.o
8
+ $(CXX) $(CXXFLAGS) $< -o $@
9
+
10
+ %.o: %.cpp
11
+ $(CXX) $(CXXFLAGS) -c $< -o $@
12
+
13
+ install:
14
+ # do nothing
15
+ EOF
16
+ end
17
+ else
18
+ open("Makefile", "wb") do |f|
19
+ f.write <<-EOF
20
+ install:
21
+ # do nothing
22
+ EOF
23
+ end
24
+ end
@@ -0,0 +1,116 @@
1
+ #include <map>
2
+ #include <string>
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <errno.h>
8
+ #include <unistd.h>
9
+ #include <sys/types.h>
10
+ #include <sys/inotify.h>
11
+
12
+ #include <errno.h>
13
+
14
+ #define EVENT_SIZE (sizeof (struct inotify_event))
15
+ #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
16
+
17
+ using namespace std;
18
+
19
+ static int _inotify_fd;
20
+ static map<int, string> _WatchedFiles;
21
+ static map<string, bool> _FileIsWatched;
22
+
23
+ // static int inotifyFlags = IN_ATTRIB | IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF;
24
+ static int inotifyFlags = IN_ATTRIB | IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF;
25
+
26
+ void maybeAddFileToWatchList(string file)
27
+ {
28
+ if (_FileIsWatched[file]) return;
29
+
30
+ int wd = inotify_add_watch(_inotify_fd, file.c_str(), inotifyFlags);
31
+ int attempts = 0;
32
+ // Files are momentarily inaccessible when they are rewritten. I couldn't
33
+ // find a good way to deal with this, so we poll 'deleted' files for 0.25s or so
34
+ // to see if they reappear.
35
+ while (wd == -1 && errno == ENOENT) {
36
+ usleep(10000);
37
+ wd = inotify_add_watch(_inotify_fd, file.c_str(), inotifyFlags);
38
+ if (attempts++ == 25) break; // try for at most about a quarter of a second
39
+ }
40
+ if (wd != -1) {
41
+ _WatchedFiles[wd] = file;
42
+ _FileIsWatched[file] = true;
43
+ }
44
+ }
45
+
46
+ // This essentially removes a file from the watchlist then
47
+ // immediately re-adds it. This is because when a file is rewritten,
48
+ // as so many editors love to do, the watchdescriptor no longer refers to
49
+ // the file, so re must re-watch the path.
50
+ void replaceFileInWatchList(int wd, string file)
51
+ {
52
+ _FileIsWatched.erase(file);
53
+ _WatchedFiles.erase(wd);
54
+ inotify_rm_watch(_inotify_fd, wd);
55
+ maybeAddFileToWatchList(file);
56
+ }
57
+
58
+ void handleStdin()
59
+ {
60
+ char line[2048];
61
+ if (fgets(line, sizeof(line), stdin) == NULL) return;
62
+ line[strlen(line)-1] = 0;
63
+
64
+ maybeAddFileToWatchList(string(line));
65
+ }
66
+
67
+ void handleInotify()
68
+ {
69
+ int length;
70
+ int i = 0;
71
+ char buffer[EVENT_BUF_LEN];
72
+ string filename;
73
+
74
+ length = read(_inotify_fd, buffer, EVENT_BUF_LEN);
75
+ if (length < 0) return;
76
+
77
+ while (i < length) {
78
+ struct inotify_event *event = (struct inotify_event *) &buffer[i];
79
+ string file = _WatchedFiles[event->wd];
80
+ if (file != "") {
81
+ printf("%s\n", file.c_str());
82
+ fflush(stdout);
83
+ replaceFileInWatchList(event->wd, file);
84
+ }
85
+
86
+ i += EVENT_SIZE + event->len;
87
+ }
88
+ }
89
+
90
+ void go()
91
+ {
92
+ fd_set rfds;
93
+ int retval;
94
+
95
+ for (;;) {
96
+ FD_ZERO(&rfds);
97
+ FD_SET(0, &rfds);
98
+ FD_SET(_inotify_fd, &rfds);
99
+
100
+ retval = select(_inotify_fd+1, &rfds, NULL, NULL, NULL);
101
+
102
+ if (retval == -1) {
103
+ // perror("select");
104
+ } else if (retval) {
105
+ if (FD_ISSET(0, &rfds)) handleStdin();
106
+ if (FD_ISSET(_inotify_fd, &rfds)) handleInotify();
107
+ }
108
+ }
109
+ }
110
+
111
+
112
+ int main(int argc, const char *argv[])
113
+ {
114
+ _inotify_fd = inotify_init();
115
+ go();
116
+ }
@@ -0,0 +1,53 @@
1
+ module Zeus
2
+ class LoadTracking
3
+ class << self
4
+
5
+ def features_loaded_by(&block)
6
+ old_features = all_features()
7
+ yield
8
+ new_features = all_features() - old_features
9
+ return new_features
10
+ end
11
+
12
+ def add_feature(file)
13
+ path = if File.exist?(File.expand_path(file))
14
+ File.expand_path(file)
15
+ else
16
+ find_in_load_path(file)
17
+ end
18
+ add_extra_feature(path) if path
19
+ end
20
+
21
+ private
22
+
23
+ def all_features
24
+ untracked = defined?($untracked_features) ? $untracked_features : []
25
+ $LOADED_FEATURES + untracked
26
+ end
27
+
28
+ def add_extra_feature(path)
29
+ $untracked_features ||= []
30
+ $untracked_features << path
31
+ end
32
+
33
+ def find_in_load_path(file)
34
+ $LOAD_PATH.map { |path| "#{path}/#{file}" }.detect{ |file| File.exist? file }
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ module Kernel
41
+
42
+ def load(file, *a)
43
+ Kernel.load(file, *a)
44
+ end
45
+
46
+ class << self
47
+ alias_method :__load_without_zeus, :load
48
+ def load(file, *a)
49
+ Zeus::LoadTracking.add_feature(file)
50
+ __load_without_zeus(file, *a)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ require "forwardable"
2
+
3
+ module Zeus
4
+ module M
5
+ ### Custom wrapper around an array of test methods
6
+ # In charge of some smart querying, filtering, sorting, etc on the the
7
+ # test methods
8
+ class TestCollection
9
+ include Enumerable
10
+ extend Forwardable
11
+ # This should act like an array, so forward some common methods over to the
12
+ # internal collection
13
+ def_delegators :@collection, :size, :<<, :each, :empty?
14
+
15
+ def initialize(collection = nil)
16
+ @collection = collection || []
17
+ end
18
+
19
+ # Slice out tests that may be within the given line.
20
+ # Returns a new TestCollection with the results.
21
+ def within(line)
22
+ # Into a new collection, filter only the tests that...
23
+ self.class.new(select do |test|
24
+ # are within the given boundary for this method
25
+ # or include everything if the line given is nil (no line)
26
+ line.nil? || (test.start_line..test.end_line).include?(line)
27
+ end)
28
+ end
29
+
30
+ # Used to line up method names in `#sprintf` when `m` aborts
31
+ def column_size
32
+ # Boil down the collection of test methods to the name of the method's
33
+ # size, then find the largest one
34
+ @column_size ||= map { |test| test.name.to_s.size }.max
35
+ end
36
+
37
+ # Be considerate when printing out tests and pre-sort them by line number
38
+ def by_line_number(&block)
39
+ # On each member of the collection, sort by line number and yield
40
+ # the block into the sorted collection
41
+ sort_by(&:start_line).each(&block)
42
+ end
43
+
44
+ def contains? test_name
45
+ @collection.each do |test|
46
+ return true if test_name.match(test.name)
47
+ end
48
+ false
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,35 @@
1
+ module Zeus
2
+ module M
3
+ ### Simple data structure for what a test method contains.
4
+ #
5
+ # Too lazy to make a class for this when it's really just a bag of data
6
+ # without any behavior.
7
+ #
8
+ # Includes the name of this method, what line on the file it begins on,
9
+ # and where it ends.
10
+ class TestMethod < Struct.new(:name, :start_line, :end_line)
11
+ # Set up a new test method for this test suite class
12
+ def self.create(suite_class, test_method, find_locations = true)
13
+ # Hopefully it's been defined as an instance method, so we'll need to
14
+ # look up the ruby Method instance for it
15
+ method = suite_class.instance_method(test_method)
16
+
17
+ if find_locations
18
+ # Ruby can find the starting line for us, so pull that out of the array
19
+ start_line = method.source_location.last
20
+
21
+ # Ruby can't find the end line however, and I'm too lazy to write
22
+ # a parser. Instead, `method_source` adds `Method#source` so we can
23
+ # deduce this ourselves.
24
+ #
25
+ # The end line should be the number of line breaks in the method source,
26
+ # added to the starting line and subtracted by one.
27
+ end_line = method.source.split("\n").size + start_line - 1
28
+ end
29
+
30
+ # Shove the given attributes into a new databag
31
+ new(test_method, start_line, end_line)
32
+ end
33
+ end
34
+ end
35
+ end