exegesis 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +5 -0
  2. data/.rvmrc +2 -0
  3. data/.yardopts +5 -0
  4. data/CHANGELOG +10 -0
  5. data/Gemfile +20 -0
  6. data/LICENSE +22 -0
  7. data/NOTES.md +214 -0
  8. data/README.md +44 -0
  9. data/Rakefile +11 -0
  10. data/TODO.md +63 -0
  11. data/bin/exegesis +15 -0
  12. data/exegesis.gemspec +23 -0
  13. data/lib/exegesis/base_directory.rb +29 -0
  14. data/lib/exegesis/directory.rb +33 -0
  15. data/lib/exegesis/file_searcher.rb +48 -0
  16. data/lib/exegesis/file_system_entity.rb +52 -0
  17. data/lib/exegesis/flyweight.rb +130 -0
  18. data/lib/exegesis/registerable.rb +58 -0
  19. data/lib/exegesis/source_file.rb +45 -0
  20. data/lib/exegesis/version.rb +4 -0
  21. data/lib/exegesis.rb +48 -0
  22. data/spec/fake_project/AUTHORS +1 -0
  23. data/spec/fake_project/Rakefile +14 -0
  24. data/spec/fake_project/config.yml +6 -0
  25. data/spec/fake_project/src/grafton.c +25 -0
  26. data/spec/fake_project/src/node.c +23 -0
  27. data/spec/fake_project/src/node.h +19 -0
  28. data/spec/fake_project/test/example2_test.c +29 -0
  29. data/spec/fake_project/test/example_test.c +12 -0
  30. data/spec/fake_project/test/test_helper.h +19 -0
  31. data/spec/helpers/delegates.rb +49 -0
  32. data/spec/helpers/set_helpers.rb +27 -0
  33. data/spec/helpers/the.rb +15 -0
  34. data/spec/helpers/they.rb +15 -0
  35. data/spec/helpers/topic.rb +82 -0
  36. data/spec/integration/flyweight_registerable_spec.rb +78 -0
  37. data/spec/integration/visitor_spec.rb +86 -0
  38. data/spec/integration_spec_helper.rb +1 -0
  39. data/spec/spec_helper.rb +36 -0
  40. data/spec/unit/base_directory_spec.rb +44 -0
  41. data/spec/unit/directory_spec.rb +44 -0
  42. data/spec/unit/file_searcher_spec.rb +82 -0
  43. data/spec/unit/flyweight_spec.rb +137 -0
  44. data/spec/unit/helpers_spec.rb +3 -0
  45. data/spec/unit/source_file_spec.rb +127 -0
  46. data/spec/unit_spec_helper.rb +1 -0
  47. metadata +158 -0
@@ -0,0 +1,78 @@
1
+ require 'integration_spec_helper'
2
+
3
+ describe Flyweight, "mixin", "other objects" do
4
+ before do
5
+ class Example
6
+ include Registerable
7
+ def initialize(parent, name, *args)
8
+ @parent = parent
9
+ @name = name
10
+ @args = args
11
+ end
12
+
13
+ attr_reader :parent, :name
14
+
15
+ def self.build_path(parent, child)
16
+ [parent.path, child].join('/')
17
+ end
18
+ end
19
+
20
+ class ParentObject
21
+ def path
22
+ "the_parent_path"
23
+ end
24
+ end
25
+ end
26
+
27
+ let(:parent) { ParentObject.new }
28
+
29
+ after do
30
+ Object.send(:remove_const, :Example)
31
+ Object.send(:remove_const, :ParentObject)
32
+ end
33
+
34
+ describe 'api' do
35
+ context 'class' do
36
+ subject { Example }
37
+ it { should respond_to :create }
38
+
39
+ context 'required' do
40
+ it { should respond_to :build_path }
41
+ end
42
+ end
43
+
44
+ context 'instance' do
45
+ subject { Example.send(:new, parent, 'n') } # to test instance API
46
+ it { should respond_to :path }
47
+ end
48
+ end
49
+
50
+ describe 'instantiation' do
51
+ it 'disallows instantiation via #new' do
52
+ expect { Example.new(parent, 'n') }.to raise_error NoMethodError
53
+ end
54
+ end
55
+
56
+ describe 'creating a new instance' do
57
+ subject { Example.create(parent, 'n') }
58
+ end
59
+
60
+ describe 'creating an instance that is already registered' do
61
+ let!(:existing_entry) { Example.create(parent, 'n') }
62
+ subject { Example.create(parent, 'n') }
63
+
64
+ it { should be existing_entry }
65
+ end
66
+
67
+ describe 'deleting an instance' do
68
+ end
69
+
70
+ describe 'retrieving an already created instance' do
71
+ context 'via #create' do
72
+ end
73
+
74
+ #find semantics, something like ['/foo/bar']
75
+ context 'via #[]' do
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,86 @@
1
+ require 'integration_spec_helper'
2
+
3
+ describe '#visit' do
4
+ let (:dir) { BaseDirectory.create('./spec/fake_project') }
5
+
6
+ context 'visitor with a proc' do
7
+ subject { proc { } }
8
+
9
+ before do
10
+ subject.stub(:call)
11
+
12
+ dir.visit(subject)
13
+ end
14
+
15
+
16
+ it { should have_received(:call).with(dir.class, dir) }
17
+ it { should_not have_received(:on_enter) }
18
+ it { should_not have_received(:on_exit) }
19
+ end
20
+
21
+ context 'visitor with a class' do
22
+ let (:visitor) { double('visitor instance') }
23
+ subject { visitor }
24
+
25
+ before do
26
+ visitor.stub(:call)
27
+ end
28
+
29
+ describe 'a visitor class with no hooks defined' do
30
+ before do
31
+ visitor.stub(:respond_to?).with(:on_enter).and_return(false)
32
+ visitor.stub(:respond_to?).with(:on_exit).and_return(false)
33
+
34
+ dir.visit(visitor)
35
+ end
36
+
37
+ it { should have_received(:call).with(dir.class, dir) }
38
+ it { should_not have_received(:on_enter) }
39
+ it { should_not have_received(:on_exit) }
40
+ end
41
+
42
+ describe 'a visitor class with the #on_enter hook defined' do
43
+ before do
44
+ visitor.stub(:respond_to?).with(:on_enter).and_return(true)
45
+ visitor.stub(:respond_to?).with(:on_exit).and_return(false)
46
+ visitor.stub(:on_enter)
47
+
48
+ dir.visit(visitor)
49
+ end
50
+
51
+ it { should have_received(:call).with(dir.class, dir) }
52
+ it { should have_received(:on_enter) }
53
+ it { should_not have_received(:on_exit) }
54
+ end
55
+
56
+ describe 'a visitor class with the #on_exit hook defined' do
57
+ before do
58
+ visitor.stub(:respond_to?).with(:on_enter).and_return(false)
59
+ visitor.stub(:respond_to?).with(:on_exit).and_return(true)
60
+ visitor.stub(:on_exit)
61
+
62
+ dir.visit(visitor)
63
+ end
64
+
65
+
66
+ it { should have_received(:call).with(dir.class, dir) }
67
+ it { should_not have_received(:on_enter) }
68
+ it { should have_received(:on_exit) }
69
+ end
70
+
71
+ describe 'a visitor class with the both hooks defined' do
72
+ before do
73
+ visitor.stub(:respond_to?).with(:on_enter).and_return(true)
74
+ visitor.stub(:respond_to?).with(:on_exit).and_return(true)
75
+ visitor.stub(:on_enter)
76
+ visitor.stub(:on_exit)
77
+
78
+ dir.visit(visitor)
79
+ end
80
+
81
+ it { should have_received(:call).with(dir.class, dir) }
82
+ it { should have_received(:on_enter) }
83
+ it { should have_received(:on_exit) }
84
+ end
85
+ end
86
+ end
@@ -0,0 +1 @@
1
+ require 'spec_helper'
@@ -0,0 +1,36 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'pry'
4
+
5
+ require 'exegesis'
6
+
7
+ require 'bahia'
8
+
9
+ require 'rspec-spies'
10
+
11
+ #include helpers
12
+ Dir["./spec/helpers/*.rb"].each { |file| require file }
13
+
14
+ RSpec.configure do |config|
15
+ config.before do
16
+ allow_message_expectations_on_nil
17
+ end
18
+
19
+ config.after do
20
+ SourceFile.clear_registry!
21
+ Directory.clear_registry!
22
+ end
23
+
24
+ config.treat_symbols_as_metadata_keys_with_true_values = true
25
+
26
+ config.include(Bahia)
27
+
28
+ config.extend(RSpec::Exegesis::DSL::Macros)
29
+ config.include(RSpec::Exegesis::DSL::Matchers)
30
+ end
31
+
32
+ class RSpec::Mocks::Mock
33
+ def inspect
34
+ "double(#{@name.inspect})"
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe BaseDirectory do
4
+ let (:root) { double('some path to a project directory').as_null_object }
5
+ let (:searcher) { double('directory searcher like FileSearcher') }
6
+ let (:dir) { double('fake directory') }
7
+ let (:file) { double('fake file') }
8
+
9
+ let (:project) { BaseDirectory.create(root, searcher) }
10
+
11
+
12
+ before do
13
+ searcher.stub(:[]).with(root + '*').and_return([dir, file])
14
+ searcher.stub(:new).and_return(searcher)
15
+ searcher.stub(:search).and_return(searcher)
16
+ end
17
+
18
+ context do
19
+ subject { project }
20
+
21
+ describe 'api' do
22
+ it { should be_a Directory }
23
+ it { should respond_to :root }
24
+ it { should respond_to :directories }
25
+ it { should respond_to :files }
26
+ end
27
+
28
+ describe '#root' do
29
+ subject { project.root }
30
+ it { should == root }
31
+ end
32
+
33
+ it { should delegate(:files).to(searcher) }
34
+ it { should delegate(:directories).to(searcher) }
35
+
36
+ #it should also provide interface for
37
+ # * creating files/directories
38
+ # - something like `directories << Directory('foo')` ?
39
+ #
40
+ # *
41
+ #
42
+ #it should also have a #visit method, see the NOTES doc for details on that
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Directory do
4
+ let (:parent) { double('parent directory') }
5
+ let (:parent_path) { 'parent/' }
6
+ let (:name) { 'subdir/' }
7
+ let (:searcher) { double('searcher') }
8
+ let (:directory) { Directory.create(parent, name, searcher) }
9
+
10
+ before do
11
+ parent.stub(:is_a?).with(Directory).and_return(true)
12
+ parent.stub(:path).and_return(parent_path)
13
+
14
+ searcher.stub(:new).and_return(searcher)
15
+ end
16
+
17
+ subject { directory }
18
+
19
+ describe 'instantiation' do
20
+ it 'disallows instantiation via #new' do
21
+ expect { Directory.new(parent, name, searcher) }.to raise_error NoMethodError
22
+ end
23
+ end
24
+
25
+ describe 'api' do
26
+ it { should respond_to :directories }
27
+ it { should respond_to :parent }
28
+ it { should respond_to :files }
29
+ it { should respond_to :path }
30
+ it { should respond_to :children }
31
+
32
+ its(:class) { should respond_to :create }
33
+ end
34
+
35
+ it { should delegate(:files).to(searcher) }
36
+ it { should delegate(:directories).to(searcher) }
37
+
38
+ describe '#path' do
39
+ subject { directory.path }
40
+
41
+ it { should be_a String }
42
+ it { should == File.join(parent_path, name) }
43
+ end
44
+ end
@@ -0,0 +1,82 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe FileSearcher do
4
+ let (:root) { double('a fake backend') }
5
+ let (:root_path) { double('a fake path') }
6
+ let (:globbed_path) { double('a fake glob of root_path with *') }
7
+ let (:file_searcher) { FileSearcher.new(root) }
8
+ let (:dir) { double('a fake directory') }
9
+ let (:file) { double('a fake file') }
10
+ let (:file_path) { double('the fake file path') }
11
+ let (:dir_path) { double('the directory file path') }
12
+
13
+ let (:fake_source_file_instance) { double('a fake SourceFile instance') }
14
+ let (:fake_directory_instance) { double('a fake Directory instance') }
15
+
16
+ before do
17
+ File.stub(:directory?).with(dir).and_return(true)
18
+ File.stub(:file?).with(dir).and_return(false)
19
+ File.stub(:basename).with(dir).and_return(dir)
20
+
21
+ File.stub(:directory?).with(file).and_return(false)
22
+ File.stub(:file?).with(file).and_return(true)
23
+ File.stub(:basename).with(file).and_return(file)
24
+
25
+ File.stub(:join).with(root_path, '*').and_return(globbed_path)
26
+ File.stub(:join).with(root_path, file).and_return(file_path)
27
+ File.stub(:join).with(root_path, dir).and_return(dir_path)
28
+
29
+ Directory.stub(:new).with(root, dir).and_return(fake_directory_instance)
30
+ SourceFile.stub(:new).with(root, file).and_return(fake_source_file_instance)
31
+
32
+ fake_source_file_instance.stub(:is_a?).with(SourceFile).and_return(true)
33
+ fake_directory_instance.stub(:is_a?).with(Directory).and_return(true)
34
+
35
+ root.stub(:path).and_return(root_path)
36
+ end
37
+
38
+ subject { file_searcher }
39
+
40
+ describe 'api' do
41
+ it { should respond_to :directories }
42
+ it { should respond_to :files }
43
+ it { should respond_to :content }
44
+ end
45
+
46
+ describe '#content' do
47
+ before do
48
+ Dir.stub(:[])
49
+ file_searcher.content
50
+ end
51
+
52
+ the(Dir) { should have_received(:[]).with(globbed_path) }
53
+ end
54
+
55
+ context do
56
+ before do
57
+ file_searcher.stub(:content).and_return([dir, file])
58
+ end
59
+
60
+ describe '#directories' do
61
+ let! (:directories) { file_searcher.directories }
62
+ subject { directories }
63
+
64
+ it { should contain(fake_directory_instance) }
65
+ it { should exclude(fake_source_file_instance) }
66
+
67
+ the_class(Directory) { should have_received(:new).with(root, dir) }
68
+ the_class(SourceFile) { should_not have_received(:new) }
69
+ end
70
+
71
+ describe '#files' do
72
+ let! (:files) { file_searcher.files }
73
+ subject { files }
74
+
75
+ it { should contain(fake_source_file_instance) }
76
+ it { should exclude(fake_directory_instance) }
77
+
78
+ the_class(Directory) { should_not have_received(:new) }
79
+ the_class(SourceFile) { should have_received(:new).with(root, file) }
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,137 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Flyweight do
4
+ let (:processor) { proc { instance_key } }
5
+ let (:flyweight) { Flyweight.new(&processor) }
6
+ let (:instance) { double('instance') }
7
+ let (:instance_key) { double('instance_key') }
8
+
9
+ subject { flyweight }
10
+
11
+ before do
12
+ processor.stub(:call).and_return(instance_key)
13
+ end
14
+
15
+ context 'shared examples' do
16
+ shared_examples_for 'flyweight unregistration' do
17
+ before { flyweight.unregister!(key) }
18
+
19
+ it { should_not have_key instance_key }
20
+ it { should_not have_key instance }
21
+
22
+ describe 'unregistering an unused key' do
23
+ it 'raises an error' do
24
+ expect { flyweight.unregister!(key) }.to raise_error Flyweight::NoEntryError
25
+ end
26
+
27
+ describe '#unregister' do
28
+ it 'raises an error' do
29
+ expect { flyweight.unregister(key) }.to_not raise_error Flyweight::NoEntryError
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ describe 'api' do
37
+ it { should respond_to :register! }
38
+ it { should respond_to :unregister! }
39
+ it { should respond_to :[] }
40
+
41
+ it { should respond_to :has_key? }
42
+
43
+ it { should respond_to :clear! }
44
+ it { should respond_to :reset! }
45
+ end
46
+
47
+ describe 'implementation' do
48
+ before { flyweight.register!(instance) }
49
+
50
+ describe '#register! and #register' do
51
+ the(:processor) { should have_received(:call).with(instance) }
52
+
53
+ describe 'registering an instance with an already-used key' do
54
+ it 'raises an error' do
55
+ expect { flyweight.register!(instance) }.to raise_error Flyweight::AlreadyRegisteredError
56
+ end
57
+
58
+ describe '#register' do
59
+ it 'does not raise an error' do
60
+ expect { flyweight.register(instance) }.to_not raise_error Flyweight::AlreadyRegisteredError
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ describe '#has_key?' do
67
+ subject { flyweight }
68
+
69
+ context 'when it has an entry for the given value' do
70
+ before { flyweight.register(instance) }
71
+
72
+ context 'by key' do
73
+ it { should have_key instance_key }
74
+ end
75
+
76
+ context 'by instance' do
77
+ it { should have_key instance }
78
+ end
79
+ end
80
+
81
+ context 'when it has no entry for the given value' do
82
+ before { flyweight.clear! }
83
+
84
+ context 'by key' do
85
+ it { should_not have_key instance_key }
86
+ end
87
+
88
+ context 'by instance' do
89
+ it { should_not have_key instance }
90
+ end
91
+ end
92
+ end
93
+
94
+ describe '#[]' do
95
+ context 'by instance' do
96
+ subject { flyweight[instance] }
97
+
98
+ it { should be instance }
99
+ end
100
+
101
+ context 'by key' do
102
+ subject { flyweight[instance_key] }
103
+
104
+ it { should be instance }
105
+ end
106
+
107
+ describe 'when flyweight does not have an entry for the value' do
108
+ before { flyweight.clear! }
109
+
110
+ context 'by instance' do
111
+ subject { flyweight[instance] }
112
+
113
+ it { should be_nil }
114
+ end
115
+
116
+ context 'by key' do
117
+ subject { flyweight[instance_key] }
118
+
119
+ it { should be_nil }
120
+ end
121
+
122
+ end
123
+ end
124
+
125
+ describe '#unregister!' do
126
+ context 'by key' do
127
+ let (:key) { instance_key }
128
+ it_behaves_like 'flyweight unregistration'
129
+ end
130
+
131
+ context 'by instance' do
132
+ let (:key) { instance }
133
+ it_behaves_like 'flyweight unregistration'
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,3 @@
1
+ require 'unit_spec_helper'
2
+
3
+ #intentionally blank
@@ -0,0 +1,127 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe SourceFile do
4
+ let(:basename) { 'fake' }
5
+ let(:extension) { '.c' }
6
+ let(:name) { basename + extension }
7
+ let(:parent) { double('directory') }
8
+
9
+ let(:full_path) { File.join(parent.path, name) }
10
+ let(:content) { double('content') }
11
+
12
+ let(:source_file) { SourceFile.create(parent, name) }
13
+
14
+ subject { source_file }
15
+
16
+ before do
17
+ parent.stub(:path).and_return('/path/to/parent/')
18
+ parent.stub(:is_a?).with(Directory).and_return(true)
19
+ File.stub(:read).with(full_path).and_return(content)
20
+ end
21
+
22
+ describe 'instantiation' do
23
+ it 'disallows instantiation via #new' do
24
+ expect { SourceFile.new(parent, name) }.to raise_error NoMethodError
25
+ end
26
+ end
27
+
28
+ describe 'api' do
29
+ context 'basic interface' do
30
+ it { should respond_to :extension }
31
+ it { should respond_to :ext }
32
+
33
+ it { should respond_to :basename }
34
+ it { should respond_to :name }
35
+
36
+ it { should respond_to :path }
37
+ it { should respond_to :content }
38
+
39
+ it { should respond_to :parent }
40
+ it { should respond_to :container }
41
+ end
42
+
43
+ context 'dependencies' do
44
+ it { should respond_to :dependencies }
45
+ it { should respond_to :depends_on }
46
+ end
47
+
48
+ pending 'language identification' do
49
+ it { should respond_to :language }
50
+ it { should respond_to :language? }
51
+ end
52
+ end
53
+
54
+ describe '#path' do
55
+ subject { source_file.path }
56
+
57
+ it { should == full_path }
58
+ end
59
+
60
+ describe '#extension' do
61
+ subject { source_file.extension }
62
+
63
+ it { should == subject.ext }
64
+ it { should == extension }
65
+ end
66
+
67
+ describe '#basename' do
68
+ subject { source_file.basename }
69
+
70
+ it { should == basename }
71
+ end
72
+
73
+ describe '#name' do
74
+ subject { source_file.name }
75
+
76
+ it { should == name }
77
+ it { should == source_file.basename + source_file.ext }
78
+ end
79
+
80
+ describe '#parent' do
81
+ subject { source_file.parent }
82
+
83
+ pending 'reimplementation' do
84
+ it 'raises an error if you try to give a parent that is not a Directory' do
85
+ expect { SourceFile.create(:not_a_dir, name) }.to raise_error ArgumentError
86
+ end
87
+ end
88
+ it { should == source_file.container }
89
+ end
90
+
91
+ describe '#content' do
92
+ before { source_file.content }
93
+
94
+ the_class(File) { should have_received(:read).with(full_path) }
95
+ end
96
+
97
+ describe '#dependencies' do
98
+ let(:file) { double('another sourcefile') }
99
+ let(:not_a_file) { double('not a sourcefile') }
100
+
101
+ before { file.stub(:is_a?).with(SourceFile).and_return(:true) }
102
+
103
+ subject { source_file.dependencies }
104
+
105
+ it { should respond_to :each }
106
+ it { should be_empty }
107
+
108
+ describe '#depends_on' do
109
+ before { source_file.depends_on(file) }
110
+
111
+ it { should =~ [file] }
112
+
113
+ it 'raises unless the dependency is a file' do
114
+ expect {
115
+ source_file.depends_on(not_a_file)
116
+ }.to raise_error InvalidDependency
117
+ end
118
+ end
119
+ end
120
+
121
+ #this should be a shared pattern between directories, sourcefiles, etc.
122
+ describe 'flyweight nature' do
123
+ #it should not create two identical instances
124
+ end
125
+
126
+ #deleting a file should delete it's instance from the flyweight
127
+ end
@@ -0,0 +1 @@
1
+ require 'spec_helper'