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.
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'