Commit a1e68a91205186287f21fb5fd1669acebcd7e79e

Authored by Robert Speicher
1 parent a8ea8d98

Rename RefExtractor to ExtractsPath

Update docs a bit
app/controllers/blame_controller.rb
1 # Controller for viewing a file's blame 1 # Controller for viewing a file's blame
2 class BlameController < ApplicationController 2 class BlameController < ApplicationController
3 -  
4 - include RefExtractor 3 + include ExtractsPath
5 4
6 layout "project" 5 layout "project"
7 6
app/controllers/blob_controller.rb
1 # Controller for viewing a file's blame 1 # Controller for viewing a file's blame
2 class BlobController < ApplicationController 2 class BlobController < ApplicationController
3 - # Thrown when given an invalid path  
4 - class InvalidPathError < StandardError; end  
5 -  
6 - include RefExtractor 3 + include ExtractsPath
7 include Gitlab::Encode 4 include Gitlab::Encode
8 5
9 layout "project" 6 layout "project"
app/controllers/tree_controller.rb
1 # Controller for viewing a repository's file structure 1 # Controller for viewing a repository's file structure
2 class TreeController < ApplicationController 2 class TreeController < ApplicationController
3 - include RefExtractor 3 + include ExtractsPath
4 4
5 layout "project" 5 layout "project"
6 6
lib/extracts_path.rb 0 → 100644
@@ -0,0 +1,114 @@ @@ -0,0 +1,114 @@
  1 +# Module providing methods for dealing with separating a tree-ish string and a
  2 +# file path string when combined in a request parameter
  3 +module ExtractsPath
  4 + extend ActiveSupport::Concern
  5 +
  6 + # Raised when given an invalid file path
  7 + class InvalidPathError < StandardError; end
  8 +
  9 + included do
  10 + if respond_to?(:before_filter)
  11 + before_filter :assign_ref_vars
  12 + end
  13 + end
  14 +
  15 + # Given a string containing both a Git tree-ish, such as a branch or tag, and
  16 + # a filesystem path joined by forward slashes, attempts to separate the two.
  17 + #
  18 + # Expects a @project instance variable to contain the active project. This is
  19 + # used to check the input against a list of valid repository refs.
  20 + #
  21 + # Examples
  22 + #
  23 + # # No @project available
  24 + # extract_ref('master')
  25 + # # => ['', '']
  26 + #
  27 + # extract_ref('master')
  28 + # # => ['master', '']
  29 + #
  30 + # extract_ref("f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG")
  31 + # # => ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
  32 + #
  33 + # extract_ref("v2.0.0/README.md")
  34 + # # => ['v2.0.0', 'README.md']
  35 + #
  36 + # extract_ref('issues/1234/app/models/project.rb')
  37 + # # => ['issues/1234', 'app/models/project.rb']
  38 + #
  39 + # # Given an invalid branch, we fall back to just splitting on the first slash
  40 + # extract_ref('non/existent/branch/README.md')
  41 + # # => ['non', 'existent/branch/README.md']
  42 + #
  43 + # Returns an Array where the first value is the tree-ish and the second is the
  44 + # path
  45 + def extract_ref(input)
  46 + pair = ['', '']
  47 +
  48 + return pair unless @project
  49 +
  50 + if input.match(/^([[:alnum:]]{40})(.+)/)
  51 + # If the ref appears to be a SHA, we're done, just split the string
  52 + pair = $~.captures
  53 + else
  54 + # Otherwise, attempt to detect the ref using a list of the project's
  55 + # branches and tags
  56 +
  57 + # Append a trailing slash if we only get a ref and no file path
  58 + id = input
  59 + id += '/' unless id.include?('/')
  60 +
  61 + valid_refs = @project.branches + @project.tags
  62 + valid_refs.select! { |v| id.start_with?("#{v}/") }
  63 +
  64 + if valid_refs.length != 1
  65 + # No exact ref match, so just try our best
  66 + pair = id.match(/([^\/]+)(.*)/).captures
  67 + else
  68 + # Partition the string into the ref and the path, ignoring the empty first value
  69 + pair = id.partition(valid_refs.first)[1..-1]
  70 + end
  71 + end
  72 +
  73 + # Remove leading slash from path
  74 + pair[1].gsub!(/^\//, '')
  75 +
  76 + pair
  77 + end
  78 +
  79 + # Assigns common instance variables for views working with Git tree-ish objects
  80 + #
  81 + # Assignments are:
  82 + #
  83 + # - @id - A string representing the joined ref and path
  84 + # - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA)
  85 + # - @path - A string representing the filesystem path
  86 + # - @commit - A CommitDecorator representing the commit from the given ref
  87 + # - @tree - A TreeDecorator representing the tree at the given ref/path
  88 + #
  89 + # If the :id parameter appears to be requesting a specific response format,
  90 + # that will be handled as well.
  91 + #
  92 + # Automatically renders `not_found!` if a valid tree path could not be
  93 + # resolved (e.g., when a user inserts an invalid path or ref).
  94 + def assign_ref_vars
  95 + # Handle formats embedded in the id
  96 + if params[:id].ends_with?('.atom')
  97 + params[:id].gsub!(/\.atom$/, '')
  98 + request.format = :atom
  99 + end
  100 +
  101 + @ref, @path = extract_ref(params[:id])
  102 +
  103 + @id = File.join(@ref, @path)
  104 +
  105 + @commit = CommitDecorator.decorate(@project.commit(@ref))
  106 +
  107 + @tree = Tree.new(@commit.tree, @project, @ref, @path)
  108 + @tree = TreeDecorator.new(@tree)
  109 +
  110 + raise InvalidPathError if @tree.invalid?
  111 + rescue NoMethodError, InvalidPathError
  112 + not_found!
  113 + end
  114 +end
lib/ref_extractor.rb
@@ -1,103 +0,0 @@ @@ -1,103 +0,0 @@
1 -# Module providing an extract_ref method for controllers working with Git  
2 -# tree-ish + path params  
3 -module RefExtractor  
4 - # Raised when given an invalid path  
5 - class InvalidPathError < StandardError; end  
6 -  
7 - # Given a string containing both a Git ref - such as a branch or tag - and a  
8 - # filesystem path joined by forward slashes, attempts to separate the two.  
9 - #  
10 - # Expects a @project instance variable to contain the active project. Used to  
11 - # check the input against a list of valid repository refs.  
12 - #  
13 - # Examples  
14 - #  
15 - # # No @project available  
16 - # extract_ref('master')  
17 - # # => ['', '']  
18 - #  
19 - # extract_ref('master')  
20 - # # => ['master', '']  
21 - #  
22 - # extract_ref("f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG")  
23 - # # => ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']  
24 - #  
25 - # extract_ref("v2.0.0/README.md")  
26 - # # => ['v2.0.0', 'README.md']  
27 - #  
28 - # extract_ref('issues/1234/app/models/project.rb')  
29 - # # => ['issues/1234', 'app/models/project.rb']  
30 - #  
31 - # # Given an invalid branch, we fall back to just splitting on the first slash  
32 - # extract_ref('non/existent/branch/README.md')  
33 - # # => ['non', 'existent/branch/README.md']  
34 - #  
35 - # Returns an Array where the first value is the tree-ish and the second is the  
36 - # path  
37 - def extract_ref(input)  
38 - pair = ['', '']  
39 -  
40 - return pair unless @project  
41 -  
42 - if input.match(/^([[:alnum:]]{40})(.+)/)  
43 - # If the ref appears to be a SHA, we're done, just split the string  
44 - pair = $~.captures  
45 - else  
46 - # Otherwise, attempt to detect the ref using a list of the project's  
47 - # branches and tags  
48 -  
49 - # Append a trailing slash if we only get a ref and no file path  
50 - id = input  
51 - id += '/' unless id.include?('/')  
52 -  
53 - valid_refs = @project.branches + @project.tags  
54 - valid_refs.select! { |v| id.start_with?("#{v}/") }  
55 -  
56 - if valid_refs.length != 1  
57 - # No exact ref match, so just try our best  
58 - pair = id.match(/([^\/]+)(.*)/).captures  
59 - else  
60 - # Partition the string into the ref and the path, ignoring the empty first value  
61 - pair = id.partition(valid_refs.first)[1..-1]  
62 - end  
63 - end  
64 -  
65 - # Remove leading slash from path  
66 - pair[1].gsub!(/^\//, '')  
67 -  
68 - pair  
69 - end  
70 -  
71 - # Assigns common instance variables for views working with Git tree-ish objects  
72 - #  
73 - # Assignments are:  
74 - #  
75 - # - @id - A string representing the joined ref and path  
76 - # - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA)  
77 - # - @path - A string representing the filesystem path  
78 - # - @commit - A CommitDecorator representing the commit from the given ref  
79 - # - @tree - A TreeDecorator representing the tree at the given ref/path  
80 - #  
81 - # Automatically renders `not_found!` if a valid tree could not be resolved  
82 - # (e.g., when a user inserts an invalid path or ref).  
83 - def assign_ref_vars  
84 - # Handle formats embedded in the id  
85 - if params[:id].ends_with?('.atom')  
86 - params[:id].gsub!(/\.atom$/, '')  
87 - request.format = :atom  
88 - end  
89 -  
90 - @ref, @path = extract_ref(params[:id])  
91 -  
92 - @id = File.join(@ref, @path)  
93 -  
94 - @commit = CommitDecorator.decorate(@project.commit(@ref))  
95 -  
96 - @tree = Tree.new(@commit.tree, @project, @ref, @path)  
97 - @tree = TreeDecorator.new(@tree)  
98 -  
99 - raise InvalidPathError if @tree.invalid?  
100 - rescue NoMethodError, InvalidPathError  
101 - not_found!  
102 - end  
103 -end  
spec/lib/extracts_path_spec.rb 0 → 100644
@@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
  1 +require 'spec_helper'
  2 +
  3 +describe ExtractsPath do
  4 + include ExtractsPath
  5 +
  6 + let(:project) { double('project') }
  7 +
  8 + before do
  9 + @project = project
  10 + project.stub(:branches).and_return(['master', 'foo/bar/baz'])
  11 + project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
  12 + end
  13 +
  14 + describe '#extract_ref' do
  15 + it "returns an empty pair when no @project is set" do
  16 + @project = nil
  17 + extract_ref('master/CHANGELOG').should == ['', '']
  18 + end
  19 +
  20 + context "without a path" do
  21 + it "extracts a valid branch" do
  22 + extract_ref('master').should == ['master', '']
  23 + end
  24 +
  25 + it "extracts a valid tag" do
  26 + extract_ref('v2.0.0').should == ['v2.0.0', '']
  27 + end
  28 +
  29 + it "extracts a valid commit ref without a path" do
  30 + extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062').should ==
  31 + ['f4b14494ef6abf3d144c28e4af0c20143383e062', '']
  32 + end
  33 +
  34 + it "falls back to a primitive split for an invalid ref" do
  35 + extract_ref('stable').should == ['stable', '']
  36 + end
  37 + end
  38 +
  39 + context "with a path" do
  40 + it "extracts a valid branch" do
  41 + extract_ref('foo/bar/baz/CHANGELOG').should == ['foo/bar/baz', 'CHANGELOG']
  42 + end
  43 +
  44 + it "extracts a valid tag" do
  45 + extract_ref('v2.0.0/CHANGELOG').should == ['v2.0.0', 'CHANGELOG']
  46 + end
  47 +
  48 + it "extracts a valid commit SHA" do
  49 + extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG').should ==
  50 + ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
  51 + end
  52 +
  53 + it "falls back to a primitive split for an invalid ref" do
  54 + extract_ref('stable/CHANGELOG').should == ['stable', 'CHANGELOG']
  55 + end
  56 + end
  57 + end
  58 +end
spec/lib/ref_extractor_spec.rb
1 require 'spec_helper' 1 require 'spec_helper'
2 2
3 -describe RefExtractor do  
4 - include RefExtractor 3 +describe ExtractsPath do
  4 + include ExtractsPath
5 5
6 let(:project) { double('project') } 6 let(:project) { double('project') }
7 7