exegesis 0.0.4 → 0.0.5
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/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
|
-
|