exegesis 0.0.2
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/.gitignore +5 -0
- data/.rvmrc +2 -0
- data/.yardopts +5 -0
- data/CHANGELOG +10 -0
- data/Gemfile +20 -0
- data/LICENSE +22 -0
- data/NOTES.md +214 -0
- data/README.md +44 -0
- data/Rakefile +11 -0
- data/TODO.md +63 -0
- data/bin/exegesis +15 -0
- data/exegesis.gemspec +23 -0
- data/lib/exegesis/base_directory.rb +29 -0
- data/lib/exegesis/directory.rb +33 -0
- data/lib/exegesis/file_searcher.rb +48 -0
- data/lib/exegesis/file_system_entity.rb +52 -0
- data/lib/exegesis/flyweight.rb +130 -0
- data/lib/exegesis/registerable.rb +58 -0
- data/lib/exegesis/source_file.rb +45 -0
- data/lib/exegesis/version.rb +4 -0
- data/lib/exegesis.rb +48 -0
- data/spec/fake_project/AUTHORS +1 -0
- data/spec/fake_project/Rakefile +14 -0
- data/spec/fake_project/config.yml +6 -0
- data/spec/fake_project/src/grafton.c +25 -0
- data/spec/fake_project/src/node.c +23 -0
- data/spec/fake_project/src/node.h +19 -0
- data/spec/fake_project/test/example2_test.c +29 -0
- data/spec/fake_project/test/example_test.c +12 -0
- data/spec/fake_project/test/test_helper.h +19 -0
- data/spec/helpers/delegates.rb +49 -0
- data/spec/helpers/set_helpers.rb +27 -0
- data/spec/helpers/the.rb +15 -0
- data/spec/helpers/they.rb +15 -0
- data/spec/helpers/topic.rb +82 -0
- data/spec/integration/flyweight_registerable_spec.rb +78 -0
- data/spec/integration/visitor_spec.rb +86 -0
- data/spec/integration_spec_helper.rb +1 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/unit/base_directory_spec.rb +44 -0
- data/spec/unit/directory_spec.rb +44 -0
- data/spec/unit/file_searcher_spec.rb +82 -0
- data/spec/unit/flyweight_spec.rb +137 -0
- data/spec/unit/helpers_spec.rb +3 -0
- data/spec/unit/source_file_spec.rb +127 -0
- data/spec/unit_spec_helper.rb +1 -0
- metadata +158 -0
data/.rvmrc
ADDED
data/.yardopts
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
|
2
|
+
* 0.0.2
|
3
|
+
Large amount of functionality in place, including BaseDirectories,
|
4
|
+
Directories, SourceFiles, and Visitors. Internal Architectural stuff also
|
5
|
+
working (objects are stored in flyweights so there are no duplicates and
|
6
|
+
everything stays synced.
|
7
|
+
|
8
|
+
* 0.0.1
|
9
|
+
|
10
|
+
Initial Release
|
data/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in exegesis.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :documentation do
|
7
|
+
gem 'rdoc'
|
8
|
+
gem 'yard'
|
9
|
+
gem 'kramdown'
|
10
|
+
end
|
11
|
+
|
12
|
+
group :development do
|
13
|
+
gem 'pry'
|
14
|
+
end
|
15
|
+
|
16
|
+
group :test do
|
17
|
+
gem 'rspec'
|
18
|
+
gem 'rspec-spies', '2.1.0'
|
19
|
+
gem 'bahia'
|
20
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Joe Fredette
|
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/NOTES.md
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
# Basic structure
|
2
|
+
|
3
|
+
## Implementation
|
4
|
+
|
5
|
+
* SourceFiles and Directories should be members of a Flyweight, and creation
|
6
|
+
should try to do a lookup first. Perhaps Celluloid can be used to do this,
|
7
|
+
with directories potentially acting as supervisors.
|
8
|
+
|
9
|
+
## Architecture
|
10
|
+
|
11
|
+
A suite of raketasks (potentially hidden behind a 'exegesis' script. Adhereing
|
12
|
+
to the following model:
|
13
|
+
|
14
|
+
class Project
|
15
|
+
HAS_MANY BaseDirectories #as a series of methods in a subclass
|
16
|
+
HAS_MANY SourceFiles
|
17
|
+
|
18
|
+
Responsibilities:
|
19
|
+
this represents the root directory of a project. It will be subclassed
|
20
|
+
into project-style specific class. Eg, a RailsProject IS_A Project, it's
|
21
|
+
BaseDirectories are, perhaps, `spec`, `app`, `lib`, and `config`. A
|
22
|
+
GemProject might have `lib`, `spec`, and `bin`, a C project might have
|
23
|
+
`test`, `src`, `vendor`, `obj`, etc.
|
24
|
+
|
25
|
+
It also provides methods like `#build_skeleton!(dir)` which take a
|
26
|
+
location in the filesystem and build the structure specified by the
|
27
|
+
project.
|
28
|
+
|
29
|
+
It also serves as a point from which we may start a `#visit` to all of
|
30
|
+
it's subdirs and files.
|
31
|
+
|
32
|
+
NB:
|
33
|
+
It might be interesting to have Projects be able to embed other projects.
|
34
|
+
This could be useful for representing, eg, tests in a C project as a
|
35
|
+
subproject with it's own file-structure and stuff. So that a CProject is
|
36
|
+
now a pair of two underlying `CSourceProject`, each of which has a `src`,
|
37
|
+
`obj`, and `vendor`, which in the one project represents the testing
|
38
|
+
setup, and the other represents the application setup. Possible problem
|
39
|
+
might be trying to get dependencies to work across projects.
|
40
|
+
|
41
|
+
----------------------------------------------------------------------------
|
42
|
+
|
43
|
+
class BaseDirectory IS_A Directory
|
44
|
+
HAS_A Root
|
45
|
+
HAS_MANY Directories
|
46
|
+
HAS_MANY SourceFiles
|
47
|
+
|
48
|
+
Responsibilities:
|
49
|
+
Expose properties of the root directory, Spawn the initial set of
|
50
|
+
directories which will recursively find all the files in the project
|
51
|
+
|
52
|
+
The class will also wrap some of the SourceFile classmacros, like #join and
|
53
|
+
#expand_path and stuff. Think along the lines of Rails.root and the like.
|
54
|
+
|
55
|
+
Collaborators:
|
56
|
+
Directory
|
57
|
+
SourceFile
|
58
|
+
|
59
|
+
----------------------------------------------------------------------------
|
60
|
+
|
61
|
+
class Directory
|
62
|
+
HAS_MANY SourceFiles
|
63
|
+
HAS_MANY Directories (Children)
|
64
|
+
HAS_A Directory (Parent)
|
65
|
+
|
66
|
+
Responsibilities:
|
67
|
+
Finds all the files and directories at a given level of the project
|
68
|
+
structure, allows for recursive informing of children -- ideally in
|
69
|
+
parallel.
|
70
|
+
|
71
|
+
Collaborators:
|
72
|
+
SourceFile
|
73
|
+
Directory
|
74
|
+
|
75
|
+
----------------------------------------------------------------------------
|
76
|
+
|
77
|
+
class SourceFile
|
78
|
+
HAS_A Extension
|
79
|
+
HAS_A Path
|
80
|
+
HAS_A Base Name
|
81
|
+
HAS_MANY SourceFiles (Dependencies)
|
82
|
+
|
83
|
+
Responsibilities:
|
84
|
+
Represents a sourcefile on disk, providing access to it's file-system
|
85
|
+
related information as well as internal information based on the language.
|
86
|
+
|
87
|
+
Notes:
|
88
|
+
This will likely work w/ an inheritance heirarchy for each programming
|
89
|
+
language. Mostly it will be one-level deep, but in the case where a
|
90
|
+
subsequent language forms a superset/subset, deeper inheritance may occur
|
91
|
+
(similarly we might have a module for shared subsets, etc).
|
92
|
+
|
93
|
+
Collaborators:
|
94
|
+
SourceFile
|
95
|
+
SourceFileFactory -- to build the appropriate subclass based on file extenstion
|
96
|
+
|
97
|
+
----------------------------------------------------------------------------
|
98
|
+
|
99
|
+
class SourceFileFactory
|
100
|
+
#snip
|
101
|
+
|
102
|
+
Responsibilities:
|
103
|
+
Provide an extensible way to build SourceFile instances appropriate to the
|
104
|
+
language the source of a given file is in.
|
105
|
+
|
106
|
+
Collaborators:
|
107
|
+
LanguageIdentifier
|
108
|
+
SourceFile
|
109
|
+
|
110
|
+
----------------------------------------------------------------------------
|
111
|
+
|
112
|
+
class LanguageIdentifier
|
113
|
+
#snip
|
114
|
+
|
115
|
+
Responsibilities:
|
116
|
+
A command object to identify the language of a given sourcefile
|
117
|
+
|
118
|
+
Collaborators:
|
119
|
+
SourceFileFactory
|
120
|
+
|
121
|
+
----------------------------------------------------------------------------
|
122
|
+
|
123
|
+
class FileSearcher
|
124
|
+
|
125
|
+
Responsibilities:
|
126
|
+
Encapsulates an API for looking through a single directory of files,
|
127
|
+
sorting them into directories/files/whatever, and providing those path
|
128
|
+
lists on demand
|
129
|
+
|
130
|
+
NB:
|
131
|
+
The aim is to isolate the minimum API with this class, so that alternative
|
132
|
+
source backends could potentially be written, eg -- a backend for
|
133
|
+
distributed sourcetrees, or w/ files in Riak or S3 or whereever
|
134
|
+
|
135
|
+
Collaborators:
|
136
|
+
Used By:
|
137
|
+
Project, Directory
|
138
|
+
Uses:
|
139
|
+
Some system-level class like Dir, FileList, or Find
|
140
|
+
|
141
|
+
|
142
|
+
# Tools
|
143
|
+
|
144
|
+
Would be nice to model these guys as actors, especially so that we and make use
|
145
|
+
of that nice async stuff for a little map-reduce-y action. Celluloid? (DCell? :])
|
146
|
+
|
147
|
+
# #visit
|
148
|
+
|
149
|
+
This is an interface which would take some kind of Visitor class, which defines
|
150
|
+
up to `n` methods (on for each model type). This method would iterate over all
|
151
|
+
of it's contents (directories/files/whatever) and apply to each the appropriate
|
152
|
+
method from the visitor, with the instance as an argument. The visitor can
|
153
|
+
potentially recursively call #visit on directories, which should also support
|
154
|
+
this interface
|
155
|
+
|
156
|
+
# DSL
|
157
|
+
|
158
|
+
w/ the restructure to use the `Project->[BaseDirs]` change, it would be useful to
|
159
|
+
have a DSL to specify a project in a simpler way than manually defining a new
|
160
|
+
subclass of `Project`. To wit, I rather like:
|
161
|
+
|
162
|
+
project 'rails' do
|
163
|
+
src_dir 'app'
|
164
|
+
src_dir 'lib'
|
165
|
+
src_dir 'db'
|
166
|
+
|
167
|
+
test_dir 'spec'
|
168
|
+
test_dir 'features'
|
169
|
+
|
170
|
+
config_dir 'config'
|
171
|
+
|
172
|
+
file 'Gemfile'
|
173
|
+
file 'Rakefile'
|
174
|
+
|
175
|
+
#etc
|
176
|
+
end
|
177
|
+
|
178
|
+
This would define an appropriate `Project` subclass, called 'RailsProject', with methods pointing to
|
179
|
+
the various subdirs.
|
180
|
+
|
181
|
+
# Features
|
182
|
+
|
183
|
+
## Core Features (Must Haves)
|
184
|
+
|
185
|
+
* Automatic Building w/ dependency discovery
|
186
|
+
- manual configuration of dependencies also allowed
|
187
|
+
- parallel builds by default
|
188
|
+
* Automatic Test Suite w/ boilerplate autogenerated
|
189
|
+
- Integrates with specific tools to do this, eg, Check or CUnit, etc.
|
190
|
+
* Handles at least C, C++, and maybe Go and Rust
|
191
|
+
|
192
|
+
## Added Features (Should Haves)
|
193
|
+
|
194
|
+
* Automatic, file-system-event based recompiles.
|
195
|
+
* Integration with other Unit testing systems
|
196
|
+
|
197
|
+
## Neat Features (Could Haves)
|
198
|
+
|
199
|
+
* Statistics on code base (LOC, Complexity metrics, etc)
|
200
|
+
* Plugin API
|
201
|
+
|
202
|
+
## Far out Features (Want-to Haves)
|
203
|
+
|
204
|
+
* Language-aware search indexing (with ElasticSearch backend?)
|
205
|
+
|
206
|
+
## Random features
|
207
|
+
|
208
|
+
* Automatically generate git helper stuff
|
209
|
+
- spawn a repo
|
210
|
+
- build the project skeleton
|
211
|
+
- set up gitignore
|
212
|
+
- set up hooks (run tests, etc)
|
213
|
+
- Set up standard docs (README, AUTHORS, LICENSE, etc)
|
214
|
+
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
** Exegesis is a pre-alpha tool. It is not recommended for public consumption **
|
2
|
+
|
3
|
+
It'll be 0.1 or better when it's ready.
|
4
|
+
|
5
|
+
# Exegesis
|
6
|
+
|
7
|
+
Exegesis is a tool for automating many parts of the development of C projects.
|
8
|
+
Following a convention-over-configuration model.
|
9
|
+
|
10
|
+
It provides tools to:
|
11
|
+
|
12
|
+
* Create skeleton projects
|
13
|
+
* Build
|
14
|
+
* Testing
|
15
|
+
* Packaging
|
16
|
+
|
17
|
+
Though C is presently the only supported language, it is the aim of Exegesis to
|
18
|
+
support tooling for other compiled languages.
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
gem 'exegesis'
|
25
|
+
|
26
|
+
And then execute:
|
27
|
+
|
28
|
+
$ bundle
|
29
|
+
|
30
|
+
Or install it yourself as:
|
31
|
+
|
32
|
+
$ gem install exegesis
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
TODO: Write usage instructions here
|
37
|
+
|
38
|
+
## Contributing
|
39
|
+
|
40
|
+
1. Fork it
|
41
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
42
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
43
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
44
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/TODO.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
1. Projects
|
2
|
+
1.1. Composite projects
|
3
|
+
|
4
|
+
2. Dependency Heirarchy (#visit should respect it)
|
5
|
+
2.1. Explicit-ordering
|
6
|
+
That is, an explicit sort based on a list of key/list pairs, the key being
|
7
|
+
the object that depends on the others being processed. We should have a
|
8
|
+
generic visitor class that can consume such a list and respect that
|
9
|
+
dependency structure when doing it's visitation.
|
10
|
+
|
11
|
+
2.2. Driven by a real example
|
12
|
+
Write a nontrivial (but simple) app in C/Go/Typescript/whatever, try to
|
13
|
+
use Exegesis to do dependency discovery, set up rake-tasks for
|
14
|
+
compilation, etc.
|
15
|
+
|
16
|
+
3. FileUtil methods
|
17
|
+
3.1 Directories should respond to stuff like `#mkdir`, `#ls`, etc. we should
|
18
|
+
have `#cd` return a BaseDirectory for the given path, perhaps. SourceFiles
|
19
|
+
should respond to `#stat`, etc. Basically load up the filesystem as methods.
|
20
|
+
|
21
|
+
4. Break up FileSystemEntity into several modules
|
22
|
+
it's a bit of a hodge-podge at the moment
|
23
|
+
|
24
|
+
5. Search
|
25
|
+
Need to be able to search for files in-project and on-path (the latter being
|
26
|
+
for referencing system-librarys). Exegesis, in the long run, is going to
|
27
|
+
calculate at least the following tasks:
|
28
|
+
|
29
|
+
* <rake task> ~ <equivalent make-related task>
|
30
|
+
|
31
|
+
* configure ~ ./configure
|
32
|
+
* default ~ make
|
33
|
+
* all ~ make all
|
34
|
+
* install ~ make install
|
35
|
+
* clean ~ make clean
|
36
|
+
* distclean ~ make distclean
|
37
|
+
|
38
|
+
In particular, configure needs to be able to calculate external dependencies
|
39
|
+
and use pkg-config to check for them (in the cases where pkg-config makes
|
40
|
+
sense). Ideally with minimal effort it could automatially scour something like
|
41
|
+
CPAN for C projects (CCAN?) or w/e and find where you have to go to install
|
42
|
+
those dependencies.
|
43
|
+
|
44
|
+
In any case, we need the ability to reference files in-context, so that an
|
45
|
+
`#include 'foo/bar'` in the src directory knows to reference `src/foo/bar`
|
46
|
+
and not `obj/foo/bar` in it's dependency setup. It would be good to also
|
47
|
+
implement `find` in terms of exegesis.
|
48
|
+
|
49
|
+
6. Celluloid
|
50
|
+
It would be very powerful to be able to have each file act independently,
|
51
|
+
especially in the case of `#visit`, because we can asynchronously spawn
|
52
|
+
visitors to do their work, and as long as the visitor can manage concurrent
|
53
|
+
access, the directories/files it visits have no shared state with anything,
|
54
|
+
and thus should be pretty easy to fit into a multi-threaded, link-free
|
55
|
+
framework like exegesis.
|
56
|
+
|
57
|
+
------ Things worth doing later ------
|
58
|
+
|
59
|
+
1. Model symlinks
|
60
|
+
2. build a visitor that outputs a `dot` graph of the folder heirarchy. bonus
|
61
|
+
points for outputting a DAG when symlinks are built
|
62
|
+
3. Performance testing.
|
63
|
+
|
data/bin/exegesis
ADDED
data/exegesis.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/exegesis/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Joe Fredette"]
|
6
|
+
gem.email = ["jfredett@gmail.com"]
|
7
|
+
gem.description = %q{A tool for automatically compiling C projects}
|
8
|
+
gem.summary = %q{Exegesis is a tool for automating many parts of the development of C projects.
|
9
|
+
Following a convention-over-configuration model, it provides tools to create
|
10
|
+
skeleton projects, as well as providing tools to automate building, testing, and
|
11
|
+
packaging.}
|
12
|
+
gem.homepage = ""
|
13
|
+
|
14
|
+
gem.add_dependency "rake"
|
15
|
+
gem.add_dependency "celluloid"
|
16
|
+
|
17
|
+
gem.files = `git ls-files`.split($\)
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
+
gem.name = "exegesis"
|
21
|
+
gem.require_paths = ["lib"]
|
22
|
+
gem.version = Exegesis::VERSION
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# class BaseDirectory IS_A Directory
|
2
|
+
# HAS_A Root
|
3
|
+
# HAS_MANY Directories
|
4
|
+
# HAS_MANY SourceFiles (files)
|
5
|
+
#
|
6
|
+
# Responsibilities:
|
7
|
+
# Expose properties of the root directory, Spawn the initial set of
|
8
|
+
# directories which will recursively find all the files in the project
|
9
|
+
#
|
10
|
+
# The class will also wrap some of the SourceFile macros, like #join and
|
11
|
+
# #expand_path and stuff. Think along the lines of Rails.root and the like.
|
12
|
+
#
|
13
|
+
# Collaborators:
|
14
|
+
# [Directory]
|
15
|
+
# [SourceFile]
|
16
|
+
class BaseDirectory < Directory
|
17
|
+
# @param root [String] the root path of the project
|
18
|
+
# @param searcher [FileSearcher] an object used to search for files in a given
|
19
|
+
# directory
|
20
|
+
def initialize(root, searcher = FileSearcher)
|
21
|
+
super(nil, root, searcher)
|
22
|
+
end
|
23
|
+
|
24
|
+
# The path to the root of the project
|
25
|
+
def path
|
26
|
+
name
|
27
|
+
end
|
28
|
+
alias root path
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# class Directory
|
2
|
+
# HAS_MANY SourceFiles
|
3
|
+
# HAS_MANY Directories (Children)
|
4
|
+
# HAS_A Directory (Parent)
|
5
|
+
#
|
6
|
+
# Responsibilities:
|
7
|
+
# Finds all the files and directories at a given level of the project
|
8
|
+
# structure, allows for recursive informing of children -- ideally in
|
9
|
+
# parallel.
|
10
|
+
#
|
11
|
+
# Collaborators:
|
12
|
+
# SourceFile
|
13
|
+
# Directory
|
14
|
+
class Directory
|
15
|
+
include FileSystemEntity
|
16
|
+
|
17
|
+
delegate [:directories, :files] => :searcher
|
18
|
+
alias children directories
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :searcher
|
23
|
+
|
24
|
+
# @param parent [Directory] the root directory or project of the project
|
25
|
+
# @param name [String] the name of the directory
|
26
|
+
# @param searcher [FileSearcher] an object used to search for files in a given
|
27
|
+
# directory
|
28
|
+
def initialize(parent, name, searcher = FileSearcher)
|
29
|
+
@parent = parent
|
30
|
+
@name = name
|
31
|
+
@searcher = searcher.new(self)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# class FileSearcher
|
2
|
+
#
|
3
|
+
# Responsibilities:
|
4
|
+
# Encapsulates an API for looking through a single directory of files,
|
5
|
+
# sorting them into directories/files/whatever, and providing those path
|
6
|
+
# lists on demand
|
7
|
+
#
|
8
|
+
# NB:
|
9
|
+
# The aim is to isolate the minimum API with this class, so that alternative
|
10
|
+
# source backends could potentially be written, eg -- a backend for
|
11
|
+
# distributed sourcetrees, or w/ files in Riak or S3 or whereever
|
12
|
+
#
|
13
|
+
# Collaborators:
|
14
|
+
# Used By:
|
15
|
+
# Project, Directory
|
16
|
+
# Uses:
|
17
|
+
# Some system-level class like Dir, FileList, or Find
|
18
|
+
class FileSearcher
|
19
|
+
# Create a new FileSearcher on the given path
|
20
|
+
#
|
21
|
+
# @param parent [Directory] the parent directory to search downward from
|
22
|
+
def initialize(parent)
|
23
|
+
@parent = parent
|
24
|
+
end
|
25
|
+
|
26
|
+
#All of the directories in the given path
|
27
|
+
def directories
|
28
|
+
content.select { |s| File.directory?(s) }.map { |s| Directory.create(parent, File.basename(s)) }
|
29
|
+
end
|
30
|
+
|
31
|
+
#All of the files in the given path
|
32
|
+
def files
|
33
|
+
content.select { |s| File.file?(s) }.map { |s| SourceFile.create(parent, File.basename(s)) }
|
34
|
+
end
|
35
|
+
|
36
|
+
#All of the content from the given path
|
37
|
+
def content
|
38
|
+
Dir[File.join(parent.path, '*')]
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
"FileSearcher(#{parent.path.inspect})"
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
attr_reader :parent
|
48
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# A collection of shared methods for Directories and SourceFiles
|
2
|
+
module FileSystemEntity
|
3
|
+
def self.included(base)
|
4
|
+
base.send(:include , Registerable)
|
5
|
+
base.send(:extend , Forwardable)
|
6
|
+
base.send(:include , Methods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module Methods
|
10
|
+
def path
|
11
|
+
File.join(parent.path, name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
"#{self.class.inspect}(#{path.inspect})"
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :parent, :name
|
19
|
+
alias container parent
|
20
|
+
|
21
|
+
def basename
|
22
|
+
File.basename(name, ext)
|
23
|
+
end
|
24
|
+
|
25
|
+
def ext
|
26
|
+
@ext || ""
|
27
|
+
end
|
28
|
+
alias extension ext
|
29
|
+
|
30
|
+
|
31
|
+
def visit(visitor)
|
32
|
+
visitor.on_enter if visitor.respond_to? :on_enter
|
33
|
+
|
34
|
+
visitor.call(self.class, self)
|
35
|
+
|
36
|
+
if respond_to?(:directories)
|
37
|
+
directories.each do |dir|
|
38
|
+
dir.visit(visitor)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if respond_to?(:files)
|
43
|
+
files.each do |file|
|
44
|
+
file.visit(visitor)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
visitor.on_exit if visitor.respond_to? :on_exit
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|