exegesis 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +11 -2
- data/NOTES.md +24 -0
- data/lib/exegesis.rb +1 -17
- data/lib/exegesis/base_directory.rb +13 -11
- data/lib/exegesis/directory.rb +24 -14
- data/lib/exegesis/file_searcher.rb +31 -29
- data/lib/exegesis/file_system_entity.rb +35 -35
- data/lib/exegesis/flyweight.rb +104 -103
- data/lib/exegesis/registerable.rb +42 -40
- data/lib/exegesis/source_file.rb +23 -21
- data/lib/exegesis/version.rb +1 -1
- data/spec/integration/flyweight_registerable_spec.rb +2 -2
- data/spec/integration/visitor_spec.rb +1 -1
- data/spec/shared/file_system_entity_examples.rb +15 -0
- data/spec/spec_helper.rb +5 -2
- data/spec/unit/base_directory_spec.rb +27 -28
- data/spec/unit/directory_spec.rb +37 -8
- data/spec/unit/file_searcher_spec.rb +10 -10
- data/spec/unit/flyweight_spec.rb +9 -9
- data/spec/unit/source_file_spec.rb +8 -7
- metadata +18 -50
- data/spec/fake_project/AUTHORS +0 -1
- data/spec/fake_project/Rakefile +0 -14
- data/spec/fake_project/config.yml +0 -6
- data/spec/fake_project/src/grafton.c +0 -25
- data/spec/fake_project/src/node.c +0 -23
- data/spec/fake_project/src/node.h +0 -19
- data/spec/fake_project/test/example2_test.c +0 -29
- data/spec/fake_project/test/example_test.c +0 -12
- data/spec/fake_project/test/test_helper.h +0 -19
data/CHANGELOG
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
|
1
|
+
* 0.0.5
|
2
|
+
* Split up the project into three projects
|
3
|
+
- Exegesis remains as the FileSystem API
|
4
|
+
- Katuv is a new tool for defining and dealing with internal DSLs
|
5
|
+
- Eisegesis is the build tool proper, which uses Katuv and Exegesis to
|
6
|
+
provide build related functionality.
|
7
|
+
* Prepare for splitting out Drosophila, which contains the flyweight
|
8
|
+
implementation (mostly so I never have to write another Flyweight again)
|
9
|
+
* Update some docs to reflect the changes
|
10
|
+
|
11
|
+
* 0.0.3 - 0.0.4
|
2
12
|
* Make sure Forwardable gem dependency gets loaded at the appropriate
|
3
13
|
load-level
|
4
14
|
* Skirt a very rare crash during tests (happens _literally_ only to my one
|
@@ -12,5 +22,4 @@
|
|
12
22
|
everything stays synced.
|
13
23
|
|
14
24
|
* 0.0.1
|
15
|
-
|
16
25
|
Initial Release
|
data/NOTES.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# Nota Bene
|
2
|
+
|
3
|
+
Much of this is out of date, now that things are split up. It remains as an
|
4
|
+
interesting relic of a time long since forgotten. Some day it will be
|
5
|
+
unceremoniously killed.
|
6
|
+
|
7
|
+
|
1
8
|
# Basic structure
|
2
9
|
|
3
10
|
## Implementation
|
@@ -212,3 +219,20 @@ the various subdirs.
|
|
212
219
|
- set up hooks (run tests, etc)
|
213
220
|
- Set up standard docs (README, AUTHORS, LICENSE, etc)
|
214
221
|
|
222
|
+
# Notes on how projects should work
|
223
|
+
|
224
|
+
* Project is the thing that interfaces with rake.
|
225
|
+
- creating a project creates a series of directory tasks, provides the
|
226
|
+
exegesis DSL for specifying package deps/whatever in whatever language
|
227
|
+
- it should automatically generate `clean`, `distclean`, and `scaffold`
|
228
|
+
tasks, the last of which is just a task that depends on all the directory
|
229
|
+
tasks
|
230
|
+
- it should use the environment for configuration.
|
231
|
+
|
232
|
+
* The Project should also automatically generate a default task which builds all
|
233
|
+
the binaries, tasks which build each binary individually, and a `install` task
|
234
|
+
which copies it to the appropriate place on the PATH
|
235
|
+
|
236
|
+
* The Project should, in particular, support multi-threaded compilation.
|
237
|
+
|
238
|
+
|
data/lib/exegesis.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
module Exegesis; end
|
1
2
|
|
2
3
|
################################################################################
|
3
4
|
#load order matters here. These are sorted into load-levels Level-0 files must
|
@@ -30,20 +31,3 @@ require 'exegesis/base_directory'
|
|
30
31
|
#-------------------------------------------------------------------------------
|
31
32
|
#load whenever
|
32
33
|
require 'exegesis/version'
|
33
|
-
|
34
|
-
################################################################################
|
35
|
-
|
36
|
-
|
37
|
-
# Exegesis is a tool for automating many parts of the development of C projects.
|
38
|
-
# Following a convention-over-configuration model.
|
39
|
-
#
|
40
|
-
# It provides tools to:
|
41
|
-
#
|
42
|
-
# * Create skeleton projects
|
43
|
-
# * Build
|
44
|
-
# * Testing
|
45
|
-
# * Packaging
|
46
|
-
#
|
47
|
-
# Though C is presently the only supported language, it is the aim of Exegesis to
|
48
|
-
# support tooling for other compiled languages.
|
49
|
-
module Exegesis; end
|
@@ -13,17 +13,19 @@
|
|
13
13
|
# Collaborators:
|
14
14
|
# [Directory]
|
15
15
|
# [SourceFile]
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
module Exegesis
|
17
|
+
class BaseDirectory < Directory
|
18
|
+
# @param root [String] the root path of the project
|
19
|
+
# @param searcher [FileSearcher] an object used to search for files in a given
|
20
|
+
# directory
|
21
|
+
def initialize(root, searcher = FileSearcher)
|
22
|
+
super(nil, root, searcher)
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
# The path to the root of the project
|
26
|
+
def path
|
27
|
+
name
|
28
|
+
end
|
29
|
+
alias root path
|
27
30
|
end
|
28
|
-
alias root path
|
29
31
|
end
|
data/lib/exegesis/directory.rb
CHANGED
@@ -11,23 +11,33 @@
|
|
11
11
|
# Collaborators:
|
12
12
|
# SourceFile
|
13
13
|
# Directory
|
14
|
-
|
15
|
-
|
14
|
+
module Exegesis
|
15
|
+
class Directory
|
16
|
+
include FileSystemEntity
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
delegate [:directories, :files] => :searcher
|
19
|
+
alias children directories
|
19
20
|
|
20
|
-
|
21
|
+
def find_directory(dirname)
|
22
|
+
directories.select { |d| d.name == dirname || d.name + '/' == dirname }.first
|
23
|
+
end
|
21
24
|
|
22
|
-
|
25
|
+
def find_file(filename)
|
26
|
+
files.select { |f| f.name == filename }.first
|
27
|
+
end
|
23
28
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@
|
30
|
-
@
|
31
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :searcher
|
32
|
+
|
33
|
+
# @param parent [Directory] the root directory or project of the project
|
34
|
+
# @param name [String] the name of the directory
|
35
|
+
# @param searcher [FileSearcher] an object used to search for files in a given
|
36
|
+
# directory
|
37
|
+
def initialize(parent, name, searcher = FileSearcher)
|
38
|
+
@parent = parent
|
39
|
+
@name = name
|
40
|
+
@searcher = searcher.new(self)
|
41
|
+
end
|
32
42
|
end
|
33
43
|
end
|
@@ -15,39 +15,41 @@
|
|
15
15
|
# Project, Directory
|
16
16
|
# Uses:
|
17
17
|
# Some system-level class like Dir, FileList, or Find
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
module Exegesis
|
19
|
+
class FileSearcher
|
20
|
+
# Create a new FileSearcher on the given path
|
21
|
+
#
|
22
|
+
# @param parent [Directory] the parent directory to search downward from
|
23
|
+
def initialize(parent, fs_interface = File)
|
24
|
+
@fs_interface = fs_interface
|
25
|
+
@parent = parent
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
#All of the directories in the given path
|
29
|
+
def directories
|
30
|
+
content.
|
31
|
+
select { |s| fs_interface.directory?(s) }.
|
32
|
+
map { |s| Directory.create(parent, fs_interface.basename(s)) }
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
#All of the files in the given path
|
36
|
+
def files
|
37
|
+
content.
|
38
|
+
select { |s| fs_interface.file?(s) }.
|
39
|
+
map { |s| SourceFile.create(parent, fs_interface.basename(s)) }
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
#All of the content from the given path
|
43
|
+
def content
|
44
|
+
Dir[File.join(parent.path, '*')]
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
def inspect
|
48
|
+
"FileSearcher(#{parent.path.inspect})"
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
+
private
|
51
52
|
|
52
|
-
|
53
|
+
attr_reader :parent, :fs_interface
|
54
|
+
end
|
53
55
|
end
|
@@ -1,52 +1,52 @@
|
|
1
1
|
# A collection of shared methods for Directories and SourceFiles
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
module Methods
|
10
|
-
def path
|
11
|
-
File.join(parent.path, name)
|
2
|
+
module Exegesis
|
3
|
+
module FileSystemEntity
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include , Registerable)
|
6
|
+
base.send(:extend , Forwardable)
|
7
|
+
base.send(:include , Methods)
|
12
8
|
end
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
module Methods
|
11
|
+
def path
|
12
|
+
File.join(parent.path, name)
|
13
|
+
end
|
17
14
|
|
18
|
-
|
19
|
-
|
15
|
+
def inspect
|
16
|
+
"#{self.class.inspect}(#{path.inspect})"
|
17
|
+
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
end
|
19
|
+
attr_reader :parent, :name
|
20
|
+
alias container parent
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
alias extension ext
|
22
|
+
def basename
|
23
|
+
File.basename(name, ext)
|
24
|
+
end
|
29
25
|
|
26
|
+
def ext
|
27
|
+
@ext || ""
|
28
|
+
end
|
29
|
+
alias extension ext
|
30
30
|
|
31
|
-
|
32
|
-
|
31
|
+
def visit(visitor)
|
32
|
+
visitor.on_enter if visitor.respond_to? :on_enter
|
33
33
|
|
34
|
-
|
34
|
+
visitor.call(self.class, self)
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
if respond_to?(:directories)
|
37
|
+
directories.each do |dir|
|
38
|
+
dir.visit(visitor)
|
39
|
+
end
|
39
40
|
end
|
40
|
-
end
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
if respond_to?(:files)
|
43
|
+
files.each do |file|
|
44
|
+
file.visit(visitor)
|
45
|
+
end
|
45
46
|
end
|
46
|
-
end
|
47
47
|
|
48
|
-
|
48
|
+
visitor.on_exit if visitor.respond_to? :on_exit
|
49
|
+
end
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
52
|
-
|
data/lib/exegesis/flyweight.rb
CHANGED
@@ -10,121 +10,122 @@
|
|
10
10
|
# SourceFile
|
11
11
|
# Directory
|
12
12
|
# Project
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
13
|
+
module Exegesis
|
14
|
+
class Flyweight
|
15
|
+
extend Forwardable
|
16
|
+
|
17
|
+
# Create an empty Flyweight with the given key-processing proc.
|
18
|
+
#
|
19
|
+
# @param key_processor [Proc] a proc which turns an instance into it's key.
|
20
|
+
def initialize(&key_processor)
|
21
|
+
clear!
|
22
|
+
|
23
|
+
if block_given?
|
24
|
+
@key_processor = key_processor
|
25
|
+
else
|
26
|
+
@key_processor = proc { |id| id }
|
27
|
+
end
|
28
|
+
|
29
|
+
self
|
26
30
|
end
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
raise AlreadyRegisteredError if has_key?(instance)
|
39
|
-
register(instance)
|
40
|
-
end
|
32
|
+
# Register an instance in the flyweight. Throw an error if the key is already
|
33
|
+
# used.
|
34
|
+
#
|
35
|
+
# @param instance [Object] the instance to register in the flyweight
|
36
|
+
# @return [Object] the instance given
|
37
|
+
# @raise [AlreadyRegisteredError] when trying to register the same key twice
|
38
|
+
def register!(instance)
|
39
|
+
raise AlreadyRegisteredError if has_key?(instance)
|
40
|
+
register(instance)
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
43
|
+
# Register an instance in the flyweight.
|
44
|
+
#
|
45
|
+
# @param instance [Object] the instance to register in the flyweight
|
46
|
+
# @return [Object] the instance given
|
47
|
+
def register(instance)
|
48
|
+
key = build_key(instance)
|
49
|
+
key_registry[key] = instance
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
52
|
+
# Remove an instance (by key or instance proper) from the flyweight. Throw an
|
53
|
+
# error if no such instance exists
|
54
|
+
#
|
55
|
+
# @param key_or_instance [Object] Either the key under which an instance is
|
56
|
+
# registered, or the instance itself.
|
57
|
+
# @return [Object] the instance deleted from the flyweight
|
58
|
+
# @raise [NoFlyweightEntryError] when trying to delete a key that isn't
|
59
|
+
# present in the flyweight
|
60
|
+
def unregister!(key_or_instance)
|
61
|
+
raise NoEntryError unless has_key?(key_or_instance)
|
62
|
+
unregister(key_or_instance)
|
63
|
+
end
|
63
64
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
65
|
+
# Remove an instance from the flyweight
|
66
|
+
#
|
67
|
+
# @param key_or_instance [Object] Either the key under which an instance is
|
68
|
+
# registered, or the instance itself.
|
69
|
+
# @return [Object] the instance deleted from the flyweight
|
70
|
+
def unregister(key_or_instance)
|
71
|
+
proxy_across_keytypes(:delete, key_or_instance)
|
72
|
+
end
|
72
73
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
74
|
+
# Whether the flyweight has the given key or instance registered
|
75
|
+
#
|
76
|
+
# @param key_or_instance [Object] Either the key under which an instance is
|
77
|
+
# registered, or the instance itself.
|
78
|
+
# @return [Boolean] True if the Flyweight has the key or instance, false
|
79
|
+
# otherwise
|
80
|
+
def has_key?(key_or_instance)
|
81
|
+
proxy_across_keytypes(:has_key?, key_or_instance)
|
82
|
+
end
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
84
|
+
# Access the entry under the given key or instance
|
85
|
+
#
|
86
|
+
# NB. If, given an instance that would generate a matching key to an already
|
87
|
+
# registered instance, but perhaps with different data, you'll get back a
|
88
|
+
# reference to the _registered_ instance.
|
89
|
+
#
|
90
|
+
# @param key_or_instance [Object] The key or instance to access.
|
91
|
+
# @return [Object, NilClass] the instance desired, or nil if it doesn't exist
|
92
|
+
def [](key_or_instance)
|
93
|
+
proxy_across_keytypes(:[], key_or_instance)
|
94
|
+
end
|
94
95
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
# Clear the Flyweight of all entries.
|
97
|
+
def clear!
|
98
|
+
@key_registry = {}
|
99
|
+
self
|
100
|
+
end
|
101
|
+
alias reset! clear!
|
101
102
|
|
102
|
-
|
103
|
-
|
104
|
-
|
103
|
+
def inspect
|
104
|
+
"Flyweight<#{object_id}, items=#{@key_registry.keys.count}>"
|
105
|
+
end
|
105
106
|
|
106
|
-
|
107
|
+
private
|
107
108
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
109
|
+
# Build a key from an instance via the key_processor
|
110
|
+
def build_key(instance)
|
111
|
+
@key_processor.call(instance)
|
112
|
+
end
|
112
113
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
114
|
+
# Proxy a method, aim to use the raw key first, but if that doesn't work, use
|
115
|
+
# the build_key helper and assume you were given an instance.
|
116
|
+
#
|
117
|
+
# NB. This is a bit dirty, but since we don't know what types we're given, we
|
118
|
+
# can't distinguish between key's and instance's without forcing the user to
|
119
|
+
# specifically tell us.
|
120
|
+
def proxy_across_keytypes(method, key)
|
121
|
+
key_registry.send(method, key) || key_registry.send(method, build_key(key))
|
122
|
+
end
|
122
123
|
|
123
|
-
|
124
|
+
attr_accessor :key_registry
|
124
125
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
# An error raised when trying to use an already used key
|
127
|
+
class AlreadyRegisteredError < ArgumentError ; end
|
128
|
+
# An error raised when trying to remove an unused key
|
129
|
+
class NoEntryError < ArgumentError ; end
|
130
|
+
end
|
129
131
|
end
|
130
|
-
|