method_log 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +5 -0
  4. data/LICENSE +19 -0
  5. data/README.md +34 -0
  6. data/Rakefile +7 -0
  7. data/bin/method_log +13 -0
  8. data/lib/method_log/api.rb +20 -0
  9. data/lib/method_log/commit.rb +50 -0
  10. data/lib/method_log/method_commit.rb +25 -0
  11. data/lib/method_log/method_definition.rb +28 -0
  12. data/lib/method_log/method_finder.rb +51 -0
  13. data/lib/method_log/repository.rb +28 -0
  14. data/lib/method_log/source_file.rb +23 -0
  15. data/lib/method_log/version.rb +3 -0
  16. data/lib/method_log.rb +2 -0
  17. data/method_log.gemspec +25 -0
  18. data/samples/repository.git/HEAD +1 -0
  19. data/samples/repository.git/config +5 -0
  20. data/samples/repository.git/description +1 -0
  21. data/samples/repository.git/hooks/README.sample +5 -0
  22. data/samples/repository.git/info/exclude +2 -0
  23. data/samples/repository.git/objects/45/0ab23bfa0bd482244c42c7e18fad84526258fc +0 -0
  24. data/samples/repository.git/objects/4c/5ba880d306780e033a5c35d3805b5f6f76aa41 +1 -0
  25. data/samples/repository.git/objects/b0/3eef6ca386d8463c28dd26f52333aba9af05dc +5 -0
  26. data/samples/repository.git/objects/e0/ec752ebc5a724d5c2880dce3126948555b9709 +0 -0
  27. data/samples/repository.git/objects/ef/ebdb1a26d03939042f2f9c09f2aa49d87d1169 +2 -0
  28. data/samples/repository.git/objects/f6/6529c35058f591594fdc9affad66ebd6a16d0f +1 -0
  29. data/samples/repository.git/refs/heads/master +1 -0
  30. data/spec/api_spec.rb +62 -0
  31. data/spec/commit_spec.rb +45 -0
  32. data/spec/method_commit_spec.rb +24 -0
  33. data/spec/method_definition_spec.rb +39 -0
  34. data/spec/method_finder_spec.rb +53 -0
  35. data/spec/source_file_spec.rb +35 -0
  36. data/spec/spec_helper.rb +1 -0
  37. metadata +129 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6a64a5c77324253051cdea911808a4d26fbcf07a
4
+ data.tar.gz: 8cf7ac058dea844d6ffbcfff7e87ce7d64bd91bf
5
+ SHA512:
6
+ metadata.gz: c1a4955bc308e0e733e3f156f44ba796a2ce639660f4988a87949ef7ab6ef85b0dd1975f540c96386cac17ff72ef912700da0d2f3477d863ff5eb6b3b2f428ea
7
+ data.tar.gz: 7176a109612715acd7b7e57f35800bb2c4c533ccf82b56ccd40dd305f67b0cc9a0f1d96cafa7233bcf24c1f9ae7e168031dd730c5b9e29e4e4b1367a6d85aa7e
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby '2.1.0'
4
+
5
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2014 by James Mead
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ ## Method Log
2
+
3
+ Trace the history of an individual method in a git repository.
4
+
5
+ ### Install
6
+
7
+ gem install method_log
8
+
9
+ ### Run
10
+
11
+ method_log <method-signature> # e.g. Foo::Bar#baz
12
+
13
+ ### Todo
14
+
15
+ * Support earlier versions of Ruby
16
+ * Support class methods
17
+ * Support namespaced classes e.g. `class Foo::Bar`
18
+ * Support for Rspec tests
19
+ * Display diffs in method implementation between commits
20
+ * Only display diffs when method implementation has changed
21
+ * Default to looking for git repo in current working directory
22
+ * Default to looking for commits in current git branch
23
+ * Maybe add as new git command or extension to existing command e.g. `git log`
24
+ * Optimise search for method definitions:
25
+ * First look in file where method was last defined
26
+ * Simple text search for files containing method name to narrow files that need to be parsed
27
+
28
+ ### Credits
29
+
30
+ Written by [James Mead](http://jamesmead.org) and the other members of [Go Free Range](http://gofreerange.com).
31
+
32
+ ### License
33
+
34
+ Released under the [MIT License](https://github.com/freerange/method_log/blob/master/LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/setup'
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
data/bin/method_log ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'method_log'
5
+ require 'method_log/repository'
6
+ require 'method_log/api'
7
+
8
+ repository = MethodLog::Repository.new(path: ARGV[0])
9
+ api = MethodLog::API.new(repository: repository)
10
+ method_commits = api.history(ARGV[1])
11
+ method_commits.each do |method_commit|
12
+ puts method_commit
13
+ end
@@ -0,0 +1,20 @@
1
+ require 'method_log/method_finder'
2
+ require 'method_log/method_commit'
3
+
4
+ module MethodLog
5
+ class API
6
+ def initialize(repository:)
7
+ @repository = repository
8
+ end
9
+
10
+ def history(method_identifier)
11
+ @repository.commits.map do |commit|
12
+ method_definitions = commit.source_files.inject([]) do |definitions, source_file|
13
+ method_finder = MethodFinder.new(source_file: source_file)
14
+ definitions += Array(method_finder.find(method_identifier))
15
+ end
16
+ MethodCommit.new(commit: commit, method_definition: method_definitions.first)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,50 @@
1
+ require 'rugged'
2
+
3
+ require 'method_log/source_file'
4
+
5
+ module MethodLog
6
+ class Commit
7
+ attr_reader :sha
8
+
9
+ def initialize(repository: repository, sha: sha)
10
+ @repository = repository
11
+ @sha = sha
12
+ @index = Rugged::Index.new
13
+ end
14
+
15
+ def add(source_file)
16
+ oid = @repository.write(source_file.source, :blob)
17
+ @index.add(path: source_file.path, oid: oid, mode: 0100644)
18
+ end
19
+
20
+ def apply
21
+ tree = @index.write_tree(@repository)
22
+ parents = @repository.empty? ? [] : [@repository.head.target].compact
23
+ user = { email: 'test@example.com', name: 'test', time: Time.now }
24
+ @sha = Rugged::Commit.create(@repository, tree: tree, parents: parents, update_ref: 'HEAD', author: user, committer: user, message: 'commit-message')
25
+ end
26
+
27
+ def source_files
28
+ commit = @repository.lookup(sha)
29
+ source_files = []
30
+ commit.tree.walk_blobs do |root, blob_hash|
31
+ path = root.empty? ? blob_hash[:name] : File.join(root, blob_hash[:name])
32
+ source = @repository.lookup(blob_hash[:oid]).text
33
+ source_files << SourceFile.new(path: path, source: source)
34
+ end
35
+ source_files
36
+ end
37
+
38
+ def ==(other)
39
+ sha == other.sha
40
+ end
41
+
42
+ def hash
43
+ sha.hash
44
+ end
45
+
46
+ def to_s
47
+ sha
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ module MethodLog
2
+ class MethodCommit
3
+ def initialize(commit:, method_definition:)
4
+ @commit = commit
5
+ @method_definition = method_definition
6
+ end
7
+
8
+ def ==(other)
9
+ (commit == other.commit) && (method_definition == other.method_definition)
10
+ end
11
+
12
+ def hash
13
+ [commit, method_definition].hash
14
+ end
15
+
16
+ def to_s
17
+ "#{commit}: #{method_definition}"
18
+ end
19
+
20
+ protected
21
+
22
+ attr_reader :commit
23
+ attr_reader :method_definition
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ module MethodLog
2
+ class MethodDefinition
3
+ def initialize(source_file:, lines:)
4
+ @source_file = source_file
5
+ @lines = lines
6
+ end
7
+
8
+ def ==(other)
9
+ (source_file == other.source_file) && (lines == other.lines)
10
+ end
11
+
12
+ def hash
13
+ [source_file, lines].hash
14
+ end
15
+
16
+ def to_s
17
+ [
18
+ "#{source_file.path}:#{lines}",
19
+ source_file.snippet(lines)
20
+ ].join($/)
21
+ end
22
+
23
+ protected
24
+
25
+ attr_reader :source_file
26
+ attr_reader :lines
27
+ end
28
+ end
@@ -0,0 +1,51 @@
1
+ require 'ripper'
2
+
3
+ require 'method_log/method_definition'
4
+
5
+ module MethodLog
6
+ class MethodFinder < Ripper
7
+ def initialize(source_file:)
8
+ super(source_file.source)
9
+ @source_file = source_file
10
+ @namespaces = []
11
+ @methods = {}
12
+ @at_scope_start = false
13
+ parse
14
+ end
15
+
16
+ def find(method_identifier)
17
+ @methods[method_identifier]
18
+ end
19
+
20
+ def on_kw(name)
21
+ case name
22
+ when 'def'
23
+ @line_number = lineno
24
+ when 'class', 'module'
25
+ @at_scope_start = true
26
+ end
27
+ end
28
+
29
+ def on_const(name)
30
+ if @at_scope_start
31
+ @namespaces << name
32
+ @at_scope_start = false
33
+ end
34
+ end
35
+
36
+ def on_def(name, *args)
37
+ identifier = "#{@namespaces.join('::')}##{name}"
38
+ lines = (@line_number - 1)..(lineno - 1)
39
+ definition = MethodDefinition.new(source_file: @source_file, lines: lines)
40
+ @methods[identifier] = definition
41
+ end
42
+
43
+ def on_class(*args)
44
+ @namespaces.pop
45
+ end
46
+
47
+ def on_module(*args)
48
+ @namespaces.pop
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ require 'rugged'
2
+
3
+ require 'method_log/commit'
4
+
5
+ module MethodLog
6
+ class Repository
7
+ attr_reader :commits
8
+
9
+ def initialize(path:)
10
+ @repository = Rugged::Repository.new(path)
11
+ @commits = []
12
+ if @repository.ref('refs/heads/master')
13
+ @repository.walk(@repository.last_commit) do |commit|
14
+ @commits << build_commit(sha: commit.oid)
15
+ end
16
+ end
17
+ end
18
+
19
+ def build_commit(sha: nil)
20
+ Commit.new(repository: @repository, sha: sha)
21
+ end
22
+
23
+ def add(commit)
24
+ commit.apply
25
+ @commits << commit
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ module MethodLog
2
+ class SourceFile
3
+ attr_reader :path
4
+ attr_reader :source
5
+
6
+ def initialize(path:, source:)
7
+ @path = path
8
+ @source = source
9
+ end
10
+
11
+ def ==(other)
12
+ (path == other.path) && (source == other.source)
13
+ end
14
+
15
+ def hash
16
+ [path, source].hash
17
+ end
18
+
19
+ def snippet(range)
20
+ lines = source.split($/)[range].join($/)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module MethodLog
2
+ VERSION = '0.0.1'
3
+ end
data/lib/method_log.rb ADDED
@@ -0,0 +1,2 @@
1
+ module MethodLog
2
+ end
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'method_log/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'method_log'
8
+ s.version = MethodLog::VERSION
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ['James Mead']
11
+ s.email = ['james@floehopper.org']
12
+ s.homepage = 'http://jamesmead.org'
13
+ s.summary = 'Trace the history of an individual method in a git repository.'
14
+ s.license = 'MIT'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- spec/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_dependency 'rugged'
22
+
23
+ s.add_development_dependency 'rake'
24
+ s.add_development_dependency 'rspec'
25
+ end
@@ -0,0 +1 @@
1
+ ref: refs/heads/master
@@ -0,0 +1,5 @@
1
+ [core]
2
+ bare = true
3
+ repositoryformatversion = 0
4
+ filemode = true
5
+ ignorecase = true
@@ -0,0 +1 @@
1
+ Unnamed repository; edit this file 'description' to name the repository.
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+ #
3
+ # Place appropriately named executable hook scripts into this directory
4
+ # to intercept various actions that git takes. See `git help hooks` for
5
+ # more information.
@@ -0,0 +1,2 @@
1
+ # File patterns to ignore; see `git help ignore` for more information.
2
+ # Lines that start with '#' are comments.
@@ -0,0 +1 @@
1
+ x�� �0�N iB���;��b��o�0 �U�bݖ ��aܯ ���%�#���-�a�H�jyb����2oC�S�&T�
@@ -0,0 +1,5 @@
1
+ x��A
2
+ 1 E]�)���&L`��DKe��[� �o���s���)l|U#��gC��G+��L
3
+ �^
4
+ I�l����
5
+ ��a��o�χ�s�'��#�`ƦaǑ�ɯ�U�]����4�
@@ -0,0 +1,2 @@
1
+ x��A
2
+ �0E]�ً��$qE��d2Q���F��F���_�ǃ/s��f�Ү���y� 0�);pN�IG*��y�Ȱ��f�E���B�(g�"r����,��m^Mӭ���}s]z���͈q�!zB��=C_���(?�Pu���1�B{
@@ -0,0 +1 @@
1
+ x+)JMU06a040031QH���+Jbx�ToOT�o�F�B����9#��
@@ -0,0 +1 @@
1
+ efebdb1a26d03939042f2f9c09f2aa49d87d1169
data/spec/api_spec.rb ADDED
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ require 'method_log/api'
4
+ require 'method_log/source_file'
5
+ require 'method_log/repository'
6
+ require 'method_log/commit'
7
+ require 'method_log/method_definition'
8
+ require 'method_log/method_commit'
9
+
10
+ describe MethodLog::API do
11
+ let(:repository_path) { File.expand_path('../repository.git', __FILE__) }
12
+
13
+ before do
14
+ FileUtils.mkdir_p(repository_path)
15
+ Rugged::Repository.init_at(repository_path, :bare)
16
+ end
17
+
18
+ after do
19
+ FileUtils.rm_rf(repository_path)
20
+ end
21
+
22
+ it 'finds class instance method in repository with two commits with single source file' do
23
+ foo_1 = MethodLog::SourceFile.new(path: 'foo.rb', source: %{
24
+ class Foo
25
+ def bar
26
+ # implementation
27
+ end
28
+ end
29
+ }.strip)
30
+
31
+ foo_2 = MethodLog::SourceFile.new(path: 'foo.rb', source: %{
32
+ # move method definition down one line
33
+ class Foo
34
+ def bar
35
+ # implementation
36
+ end
37
+ end
38
+ }.strip)
39
+
40
+ repository = MethodLog::Repository.new(path: repository_path)
41
+
42
+ commit_1 = repository.build_commit
43
+ commit_1.add(foo_1)
44
+ repository.add(commit_1)
45
+
46
+ commit_2 = repository.build_commit
47
+ commit_2.add(foo_2)
48
+ repository.add(commit_2)
49
+
50
+ repository = MethodLog::Repository.new(path: repository_path)
51
+ api = MethodLog::API.new(repository: repository)
52
+ method_commits = api.history('Foo#bar')
53
+
54
+ method_definition_1 = MethodLog::MethodDefinition.new(source_file: foo_1, lines: 1..3)
55
+ method_definition_2 = MethodLog::MethodDefinition.new(source_file: foo_2, lines: 2..4)
56
+
57
+ method_commit_1 = MethodLog::MethodCommit.new(commit: commit_1, method_definition: method_definition_1)
58
+ method_commit_2 = MethodLog::MethodCommit.new(commit: commit_2, method_definition: method_definition_2)
59
+
60
+ expect(method_commits).to eq([method_commit_2, method_commit_1])
61
+ end
62
+ end
@@ -0,0 +1,45 @@
1
+ require 'method_log/repository'
2
+ require 'method_log/commit'
3
+ require 'method_log/source_file'
4
+
5
+ describe MethodLog::Commit do
6
+ let(:sha) { 'b54d38bbd989f4b54c38fd77767d89d1' }
7
+ let(:commit) { MethodLog::Commit.new(sha: sha) }
8
+ let(:commit_with_same_sha) { MethodLog::Commit.new(sha: sha) }
9
+
10
+ it 'is equal to another commit with same SHA' do
11
+ expect(commit).to eq(commit_with_same_sha)
12
+ end
13
+
14
+ it 'has same hash as another commit with same SHA' do
15
+ expect(commit.hash).to eq(commit_with_same_sha.hash)
16
+ end
17
+
18
+ context 'using a real git repository' do
19
+ let(:repository_path) { File.expand_path('../repository.git', __FILE__) }
20
+
21
+ before do
22
+ FileUtils.mkdir_p(repository_path)
23
+ Rugged::Repository.init_at(repository_path, :bare)
24
+ end
25
+
26
+ after do
27
+ FileUtils.rm_rf(repository_path)
28
+ end
29
+
30
+ it 'stores source files added to a commit in the repository against a real commit' do
31
+ source_one = MethodLog::SourceFile.new(path: 'path/to/source_one.rb', source: 'source-one')
32
+ source_two = MethodLog::SourceFile.new(path: 'path/to/source_two.rb', source: 'source-two')
33
+
34
+ repository = MethodLog::Repository.new(path: repository_path)
35
+ commit = repository.build_commit
36
+ commit.add(source_one)
37
+ commit.add(source_two)
38
+ commit.apply
39
+
40
+ repository = MethodLog::Repository.new(path: repository_path)
41
+ commit = repository.commits.first
42
+ expect(commit.source_files).to eq([source_one, source_two])
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ require 'method_log/method_commit'
2
+ require 'method_log/commit'
3
+ require 'method_log/source_file'
4
+ require 'method_log/method_definition'
5
+
6
+ describe MethodLog::MethodCommit do
7
+ let(:commit) { MethodLog::Commit.new }
8
+ let(:source_file) { MethodLog::SourceFile.new(path: '/path/to/source.rb', source: 'source') }
9
+ let(:method_definition) { MethodLog::MethodDefinition.new(source_file: source_file, lines: 5..7) }
10
+ let(:method_commit) {
11
+ MethodLog::MethodCommit.new(commit: commit, method_definition: method_definition)
12
+ }
13
+ let(:method_commit_with_same_commit_and_method_definition) {
14
+ MethodLog::MethodCommit.new(commit: commit, method_definition: method_definition)
15
+ }
16
+
17
+ it 'is equal to another method commit with same commit and method definition' do
18
+ expect(method_commit).to eq(method_commit_with_same_commit_and_method_definition)
19
+ end
20
+
21
+ it 'has same hash as another method commit with same commit and method definition' do
22
+ expect(method_commit.hash).to eq(method_commit_with_same_commit_and_method_definition.hash)
23
+ end
24
+ end
@@ -0,0 +1,39 @@
1
+ require 'method_log/method_definition'
2
+ require 'method_log/source_file'
3
+
4
+ describe MethodLog::MethodDefinition do
5
+ let(:source_file) do
6
+ MethodLog::SourceFile.new(path: 'path/to/source.rb', source: %{
7
+ class Foo
8
+ def bar
9
+ # implementation
10
+ end
11
+ end
12
+ }.strip)
13
+ end
14
+
15
+ it 'is equal to another method definition with same source file and line numbers' do
16
+ definition_one = MethodLog::MethodDefinition.new(source_file: source_file, lines: 1..3)
17
+ definition_two = MethodLog::MethodDefinition.new(source_file: source_file, lines: 1..3)
18
+
19
+ expect(definition_one).to eq(definition_two)
20
+ end
21
+
22
+ it 'has same hash as another method definition with same path and line numbers' do
23
+ definition_one = MethodLog::MethodDefinition.new(source_file: source_file, lines: 1..3)
24
+ definition_two = MethodLog::MethodDefinition.new(source_file: source_file, lines: 1..3)
25
+
26
+ expect(definition_one.hash).to eq(definition_two.hash)
27
+ end
28
+
29
+ it 'describes method definition' do
30
+ definition = MethodLog::MethodDefinition.new(source_file: source_file, lines: 1..3)
31
+
32
+ expect(definition.to_s).to eq(%{
33
+ path/to/source.rb:1..3
34
+ def bar
35
+ # implementation
36
+ end
37
+ }.strip)
38
+ end
39
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ require 'method_log/source_file'
4
+ require 'method_log/method_finder'
5
+
6
+ describe MethodLog::MethodFinder do
7
+ it 'finds definition of instance method on class' do
8
+ foo = MethodLog::SourceFile.new(path: 'foo.rb', source: %{
9
+ class Foo
10
+ def bar
11
+ # implementation
12
+ end
13
+ end
14
+ }.strip)
15
+
16
+ method_finder = MethodLog::MethodFinder.new(source_file: foo)
17
+ method_definition = method_finder.find('Foo#bar')
18
+
19
+ expect(method_definition).to eq(MethodLog::MethodDefinition.new(source_file: foo, lines: 1..3))
20
+ end
21
+
22
+ it 'finds definition of instance method on module' do
23
+ foo = MethodLog::SourceFile.new(path: 'foo.rb', source: %{
24
+ module Foo
25
+ def bar
26
+ # implementation
27
+ end
28
+ end
29
+ }.strip)
30
+
31
+ method_finder = MethodLog::MethodFinder.new(source_file: foo)
32
+ method_definition = method_finder.find('Foo#bar')
33
+
34
+ expect(method_definition).to eq(MethodLog::MethodDefinition.new(source_file: foo, lines: 1..3))
35
+ end
36
+
37
+ it 'finds definition of instance method on class within module' do
38
+ foo = MethodLog::SourceFile.new(path: 'foo.rb', source: %{
39
+ module Foo
40
+ class Bar
41
+ def baz
42
+ # implementation
43
+ end
44
+ end
45
+ end
46
+ }.strip)
47
+
48
+ method_finder = MethodLog::MethodFinder.new(source_file: foo)
49
+ method_definition = method_finder.find('Foo::Bar#baz')
50
+
51
+ expect(method_definition).to eq(MethodLog::MethodDefinition.new(source_file: foo, lines: 2..4))
52
+ end
53
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ require 'method_log/source_file'
4
+
5
+ describe MethodLog::SourceFile do
6
+ it 'is equal to another source file with same path and source' do
7
+ file_one = MethodLog::SourceFile.new(path: 'path/to/source.rb', source: 'source-one')
8
+ file_two = MethodLog::SourceFile.new(path: 'path/to/source.rb', source: 'source-one')
9
+
10
+ expect(file_one).to eq(file_two)
11
+ end
12
+
13
+ it 'has same hash as another source file with same path and source' do
14
+ file_one = MethodLog::SourceFile.new(path: 'path/to/source.rb', source: 'source-one')
15
+ file_two = MethodLog::SourceFile.new(path: 'path/to/source.rb', source: 'source-one')
16
+
17
+ expect(file_one.hash).to eq(file_two.hash)
18
+ end
19
+
20
+ it 'describes source file' do
21
+ file = MethodLog::SourceFile.new(path: 'path/to/source.rb', source: %{
22
+ class Foo
23
+ def bar
24
+ # implementation
25
+ end
26
+ end
27
+ }.strip)
28
+
29
+ expect(file.snippet(1..3).strip).to eq(%{
30
+ def bar
31
+ # implementation
32
+ end
33
+ }.strip)
34
+ end
35
+ end
@@ -0,0 +1 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: method_log
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - James Mead
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rugged
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email:
57
+ - james@floehopper.org
58
+ executables:
59
+ - method_log
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE
66
+ - README.md
67
+ - Rakefile
68
+ - bin/method_log
69
+ - lib/method_log.rb
70
+ - lib/method_log/api.rb
71
+ - lib/method_log/commit.rb
72
+ - lib/method_log/method_commit.rb
73
+ - lib/method_log/method_definition.rb
74
+ - lib/method_log/method_finder.rb
75
+ - lib/method_log/repository.rb
76
+ - lib/method_log/source_file.rb
77
+ - lib/method_log/version.rb
78
+ - method_log.gemspec
79
+ - samples/repository.git/HEAD
80
+ - samples/repository.git/config
81
+ - samples/repository.git/description
82
+ - samples/repository.git/hooks/README.sample
83
+ - samples/repository.git/info/exclude
84
+ - samples/repository.git/objects/45/0ab23bfa0bd482244c42c7e18fad84526258fc
85
+ - samples/repository.git/objects/4c/5ba880d306780e033a5c35d3805b5f6f76aa41
86
+ - samples/repository.git/objects/b0/3eef6ca386d8463c28dd26f52333aba9af05dc
87
+ - samples/repository.git/objects/e0/ec752ebc5a724d5c2880dce3126948555b9709
88
+ - samples/repository.git/objects/ef/ebdb1a26d03939042f2f9c09f2aa49d87d1169
89
+ - samples/repository.git/objects/f6/6529c35058f591594fdc9affad66ebd6a16d0f
90
+ - samples/repository.git/refs/heads/master
91
+ - spec/api_spec.rb
92
+ - spec/commit_spec.rb
93
+ - spec/method_commit_spec.rb
94
+ - spec/method_definition_spec.rb
95
+ - spec/method_finder_spec.rb
96
+ - spec/source_file_spec.rb
97
+ - spec/spec_helper.rb
98
+ homepage: http://jamesmead.org
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.2.0
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Trace the history of an individual method in a git repository.
122
+ test_files:
123
+ - spec/api_spec.rb
124
+ - spec/commit_spec.rb
125
+ - spec/method_commit_spec.rb
126
+ - spec/method_definition_spec.rb
127
+ - spec/method_finder_spec.rb
128
+ - spec/source_file_spec.rb
129
+ - spec/spec_helper.rb