ginatra 3.0.1 → 4.0.0

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 (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -15
  3. data/.travis.yml +7 -6
  4. data/CONTRIBUTING.md +30 -0
  5. data/Gemfile +1 -9
  6. data/LICENSE.txt +30 -0
  7. data/README.md +63 -114
  8. data/Rakefile +10 -12
  9. data/bin/ginatra +79 -63
  10. data/config.ru +35 -3
  11. data/ginatra.gemspec +29 -18
  12. data/lib/ginatra.rb +161 -148
  13. data/lib/ginatra/config.rb +18 -121
  14. data/lib/ginatra/errors.rb +10 -0
  15. data/lib/ginatra/helpers.rb +154 -139
  16. data/lib/ginatra/repo.rb +67 -82
  17. data/lib/ginatra/repo_list.rb +25 -18
  18. data/lib/ginatra/repo_stats.rb +93 -0
  19. data/lib/ginatra/version.rb +4 -0
  20. data/lib/git/webby.rb +292 -0
  21. data/lib/git/webby/extensions.rb +10 -0
  22. data/lib/git/webby/http_backend.rb +177 -0
  23. data/lib/sinatra/partials.rb +1 -1
  24. data/public/css/application.css +6 -0
  25. data/public/css/custom.css +57 -0
  26. data/public/css/lib/bootstrap-responsive.min.css +9 -0
  27. data/public/css/lib/bootstrap.min.css +9 -0
  28. data/public/css/lib/highlight.css +209 -0
  29. data/public/img/glyphicons-halflings-white.png +0 -0
  30. data/public/img/glyphicons-halflings.png +0 -0
  31. data/public/img/spin.gif +0 -0
  32. data/public/js/application.js +5 -0
  33. data/public/js/custom.js +51 -0
  34. data/public/js/lib/bootstrap.min.js +6 -0
  35. data/public/js/lib/jquery.lazyload.min.js +2 -0
  36. data/public/js/lib/jquery.min.js +2 -0
  37. data/public/js/lib/jquery.pjax.js +739 -0
  38. data/repos/README.md +21 -8
  39. data/spec/ginatra/helpers_spec.rb +95 -0
  40. data/spec/ginatra/repo_list_spec.rb +66 -0
  41. data/spec/ginatra/repo_spec.rb +78 -0
  42. data/spec/ginatra/repo_stats_spec.rb +27 -0
  43. data/spec/ginatra_spec.rb +121 -0
  44. data/spec/spec_helper.rb +8 -17
  45. data/views/404.erb +18 -0
  46. data/views/500.erb +18 -0
  47. data/views/_footer.erb +7 -0
  48. data/views/_header.erb +12 -6
  49. data/views/_tree_nav.erb +53 -0
  50. data/views/atom.erb +32 -0
  51. data/views/blob.erb +27 -8
  52. data/views/commit.erb +95 -17
  53. data/views/empty_repo.erb +10 -0
  54. data/views/index.erb +27 -11
  55. data/views/layout.erb +16 -20
  56. data/views/log.erb +74 -54
  57. data/views/stats.erb +89 -0
  58. data/views/tree.erb +32 -20
  59. metadata +168 -94
  60. data/bin/ginatra-daemon +0 -87
  61. data/bin/ginatra-directory +0 -55
  62. data/bin/ginatra-server +0 -27
  63. data/bin/ginatra-setup +0 -28
  64. data/lib/ginatra/graph_commit.rb +0 -77
  65. data/public/img/add.png +0 -0
  66. data/public/img/diff.png +0 -0
  67. data/public/img/doc.png +0 -0
  68. data/public/img/rm.png +0 -0
  69. data/public/img/tree.png +0 -0
  70. data/public/src/branch-graph.js +0 -170
  71. data/public/src/colour.css +0 -86
  72. data/public/src/commit.css +0 -211
  73. data/public/src/ginatra.js +0 -7
  74. data/public/src/github.css +0 -129
  75. data/public/src/graph.css +0 -9
  76. data/public/src/highlight.pack.js +0 -1
  77. data/public/src/index.css +0 -92
  78. data/public/src/lists.css +0 -25
  79. data/public/src/raphael.js +0 -7
  80. data/public/src/reset.css +0 -49
  81. data/public/src/table.css +0 -33
  82. data/public/src/type.css +0 -30
  83. data/rackup.ru +0 -5
  84. data/spec/graph_commit_spec.rb +0 -54
  85. data/spec/repo_list_spec.rb +0 -84
  86. data/spec/repo_spec.rb +0 -61
  87. data/views/_actor_box.erb +0 -13
  88. data/views/_commit_info_box.erb +0 -27
  89. data/views/_tree_part.erb +0 -11
  90. data/views/atom.builder +0 -32
  91. data/views/graph.erb +0 -15
@@ -1,130 +1,27 @@
1
- require "yaml"
2
- require "fileutils"
3
- require "logger"
1
+ require 'yaml'
2
+ require 'ostruct'
4
3
 
5
4
  module Ginatra
5
+ def self.config
6
+ @config ||= OpenStruct.new load_config
7
+ end
6
8
 
7
- # A Wrapper for the ginatra configuration variables,
8
- # including methods to load, dump and lookup keys
9
- # using just the class.
10
- class Config
11
-
12
- current_path = File.expand_path("#{File.dirname(__FILE__)}")
13
-
14
- # A default path for our configuration variables!
15
- CONFIG_PATH = File.expand_path("~/.ginatra/config.yml")
16
-
17
- # A default config that we fall back to if no file is found.
18
- DEFAULT_CONFIG = {
19
- :git_dirs => [File.expand_path("#{current_path}/../../repos/*")],
20
- :ignored_files => ['README.md'],
21
- :description => "View My Git Repositories",
22
- :port => 9797,
23
- :host => "0.0.0.0",
24
- :prefix => "/"
25
- }
26
-
27
- def self.logger
28
- return @logger if @logger
29
-
30
- log_file = Ginatra::Config[:log_file] || STDOUT
31
-
32
- # create log_file location
33
- # The log_file config option should be an absolute file system path
34
- # It doesn't have to exist, but ginatra should have the proper file system privileges to create the directories
35
- # and files along the specified path
36
- unless log_file == STDOUT
37
- parent_dir, separator, file_component = log_file.rpartition("/")
38
- FileUtils.mkdir_p parent_dir
39
- FileUtils.touch log_file
40
- end
41
-
42
- # determine log level from config file
43
- # The log_level config option should be one of the Logger::Severity constant names (case doesn't matter)
44
- # example: :log_level: debug
45
- log_level = Ginatra::Config[:log_level]
46
-
47
- if log_level.nil?
48
- log_level = Logger::WARN
49
- else
50
- log_level = Logger.const_get(log_level.to_s.upcase.to_sym)
51
- log_level = Logger::WARN if log_level.nil?
52
- end
53
-
54
- @logger = Logger.new(log_file)
55
- @logger.level = log_level
56
- @logger.formatter = Proc.new {|s, t, n, msg| "[#{t}] #{msg}\n"}
57
- @logger
58
- end
59
-
60
- def self.safe_setup
61
- unless File.exist?(CONFIG_PATH)
62
- FileUtils.mkdir_p(File.dirname(CONFIG_PATH))
63
- File.open(CONFIG_PATH, 'w') do |f|
64
- YAML.dump(DEFAULT_CONFIG, f)
65
- end
66
- end
67
- end
68
-
69
- # Loads the configuration and merges it with
70
- # the default configuration.
71
- #
72
- # @return [Hash] config a hash of the configuration options
73
- def self.load!
74
- loaded_config = {}
75
- @config = DEFAULT_CONFIG.dup
76
- if File.size(CONFIG_PATH) == 0
77
- dump!
78
- else
79
- loaded_config = YAML.load_file(CONFIG_PATH)
80
- @config.merge!(loaded_config)
81
- end
82
- @config
83
- end
84
-
85
- # Dumps the _current_ configuration to +CONFIG_PATH+
86
- # again WITHOUT regard for what's already there.
87
- #
88
- # Very Destructive Method. Use with care!
89
- def self.dump!
90
- File.open(CONFIG_PATH, 'w') do |f|
91
- YAML.dump(@config, f)
92
- end
93
- end
9
+ # Loads the configuration and merges it with
10
+ # custom configuration if necessary.
11
+ #
12
+ # @return [Hash] config a hash of the configuration options
13
+ def self.load_config
14
+ current_path = File.expand_path(File.dirname(__FILE__))
15
+ custom_config_file = File.expand_path("~/.ginatra/config.yml")
16
+ default_config_file = File.expand_path("#{current_path}/../../config.yml")
94
17
 
95
- # Allows us to do many things.
96
- #
97
- # The first is respond to any hash methods
98
- # and execute them on the +@config+ hash.
99
- #
100
- # The second is to do something like
101
- # +Ginatra::Config.port+ instead of something
102
- # like +Ginatra::Config[:port]+
103
- #
104
- # @return depends on what's in the config hash.
105
- def self.method_missing(sym, *args, &block)
106
- if @config.respond_to?(sym)
107
- @config.send(sym, *args, &block)
108
- elsif @config.has_key?(sym)
109
- @config[sym]
110
- else
111
- super
112
- end
113
- end
18
+ config = YAML.load_file(default_config_file)
114
19
 
115
- # This is so that we can be clever by using
116
- # +#try()+ and so that this mirrors +method_missing+.
117
- #
118
- # @see Ginatra::Config.method_missing
119
- def self.respond_to?(name)
120
- if @config.respond_to?(name)
121
- true
122
- elsif @config.has_key?(name)
123
- true
124
- else
125
- super
126
- end
20
+ if File.exist?(custom_config_file)
21
+ custom_config = YAML.load_file(custom_config_file)
22
+ config.merge!(custom_config)
127
23
  end
128
24
 
25
+ config
129
26
  end
130
27
  end
@@ -0,0 +1,10 @@
1
+ module Ginatra
2
+ # A standard error class for inheritance.
3
+ class Error < StandardError; end
4
+
5
+ # Raised when repo not found in list.
6
+ class RepoNotFound < Error; end
7
+
8
+ # Raised when repo ref not found.
9
+ class InvalidRef < Error; end
10
+ end
@@ -1,30 +1,89 @@
1
- require "digest/md5"
1
+ require 'digest/md5'
2
2
 
3
3
  module Ginatra
4
- # Helpers used in the views usually,
5
- # but not exclusively.
4
+ # Helpers used in the views, and not only.
6
5
  module Helpers
6
+ # Escapes string to HTML entities
7
+ def h(text)
8
+ Rack::Utils.escape_html(text)
9
+ end
10
+
11
+ # Checks X-PJAX header
12
+ def is_pjax?
13
+ request.env['HTTP_X_PJAX']
14
+ end
7
15
 
8
- # constructs the URL used in the layout's base tag
9
- def prefix_url(rest_of_url="")
10
- prefix = Ginatra::Config[:prefix].to_s
16
+ # Sets title for pages
17
+ def title(*args)
18
+ @title ||= []
19
+ @title_options ||= { headline: nil, sitename: nil }
20
+ options = args.last.is_a?(Hash) ? args.pop : {}
11
21
 
12
- if prefix.length > 0 && prefix[-1].chr == "/"
22
+ @title += args
23
+ @title_options.merge!(options)
24
+
25
+ t = @title.clone
26
+ t << @title_options[:headline]
27
+ t << @title_options[:sitename]
28
+ t.compact.join ' - '
29
+ end
30
+
31
+ # Constructs the URL used in the layout's base tag
32
+ def prefix_url(rest_of_url='')
33
+ prefix = Ginatra.config.prefix.to_s
34
+
35
+ if prefix.length > 0 && prefix[-1].chr == '/'
13
36
  prefix.chop!
14
37
  end
15
38
 
16
39
  "#{prefix}/#{rest_of_url}"
17
40
  end
18
41
 
19
- # takes an email and returns a url to a secure gravatar
42
+ # Returns hint to set repository description
43
+ def empty_description_hint_for(repo)
44
+ return '' unless repo.description.empty?
45
+ hint_text = "Edit `#{repo.path}description` file to set the repository description."
46
+ "<span class='icon-exclamation-sign' title='#{hint_text}'></span>"
47
+ end
48
+
49
+ # Returns file icon depending on filemode
50
+ def file_icon(filemode)
51
+ case filemode
52
+ # symbolic link (120000)
53
+ when 40960 then "<span class='icon-share-alt'></span>"
54
+ # executable file (100755)
55
+ when 33261 then "<span class='icon-asterisk'></span>"
56
+ else "<span class='icon-file'></span>"
57
+ end
58
+ end
59
+
60
+ # Masks original email
61
+ def secure_mail(email)
62
+ local, domain = email.split('@')
63
+ "#{local[0..3]}...@#{domain}"
64
+ end
65
+
66
+ # Takes an email and returns an image tag with gravatar
20
67
  #
21
68
  # @param [String] email the email address
22
- # @return [String] the url to the gravatar
23
- def gravatar_url(email)
24
- "https://secure.gravatar.com/avatar/#{Digest::MD5.hexdigest(email)}?s=40"
69
+ # @param [Hash] options alt, class and size options for image tag
70
+ # @return [String] html image tag
71
+ def gravatar_image_tag(email, options={})
72
+ alt = options.fetch(:alt, email.gsub(/@\S*/, ''))
73
+ size = options.fetch(:size, 40)
74
+ url = "https://secure.gravatar.com/avatar/#{Digest::MD5.hexdigest(email)}?s=#{size}"
75
+
76
+ if options[:lazy]
77
+ placeholder = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
78
+ tag = "<img data-original='#{url}' src='#{placeholder}' alt='#{h alt}' height='#{size}' width='#{size}' class='js-lazy #{options[:class]}'>"
79
+ else
80
+ tag = "<img src='#{url}' alt='#{h alt}' height='#{size}' width='#{size}'#{" class='#{options[:class]}'" if options[:class]}>"
81
+ end
82
+
83
+ tag
25
84
  end
26
85
 
27
- # reformats the date into a user friendly date with html entities
86
+ # Reformats the date into a user friendly date with html entities
28
87
  #
29
88
  # @param [#strftime] date object to format nicely
30
89
  # @return [String] html string formatted using
@@ -33,116 +92,118 @@ module Ginatra
33
92
  date.strftime("%b %d, %Y &ndash; %H:%M")
34
93
  end
35
94
 
36
- # displays the actor box easily.
37
- #
38
- # Internally, it calls the +#partial+ method
39
- # @see Sinatra::Partials#partial
40
- #
41
- # @param [Grit::Actor] actor the Grit Actor Object
42
- # @param [#to_s] role the role that the object has.
43
- # @param [#strftime] date the date that the actor acted on.
95
+ # Returns an html time tag for the given time
44
96
  #
45
- # @return [String] a string that contains the box for the actor.
46
- def actor_box(actor, role, date)
47
- partial(:actor_box, :locals => { :actor => actor, :role => role, :date => date })
97
+ # @param [Time] time object
98
+ # @return [String] time tag formatted using
99
+ # +"%B %d, %Y %H:%M"+
100
+ def time_tag(time)
101
+ datetime = time.strftime('%Y-%m-%dT%H:%M:%S%z')
102
+ title = time.strftime('%Y-%m-%d %H:%M:%S')
103
+ "<time datetime='#{datetime}' title='#{title}'>#{time.strftime('%B %d, %Y %H:%M')}</time>"
48
104
  end
49
105
 
50
- # works out what actor boxes need to be displayed.
106
+ # Returns a string including the link to download a patch for a certain
107
+ # commit to the repo
51
108
  #
52
- # Will always display the committer box, and will only display
53
- # the author box if it's different to the committer
109
+ # @param [Rugged::Commit] commit the commit you want a patch for
110
+ # @param [String] repo_param the url-sanitised name for the repo
111
+ # (for the link path)
54
112
  #
55
- # @param [Grit::Commit] commit the commit in question
56
- # @return [String] a string representing the HTML actor boxes
57
- def actor_boxes(commit)
58
- o = actor_box(commit.committer, :committer, commit.committed_date)
59
- if commit.author.name != commit.committer.name
60
- o = actor_box(commit.author, :author, commit.authored_date) + o
61
- end
113
+ # @return [String] the HTML link to the patch
114
+ def patch_link(commit, repo_param)
115
+ patch_url = prefix_url("#{repo_param}/commit/#{commit.oid}.patch")
116
+ "<a href='#{patch_url}'>Download Patch</a>"
62
117
  end
63
118
 
64
- # spits out a link to a certain reference.
119
+ # Spits out a HTML link to the atom feed for a given ref of a given repo
65
120
  #
66
- # @param [Grit::Ref] ref grit ref object
67
- # @param [String] repo_param the url-sanitised-name for the repo
68
- # (for the link path)
121
+ # @param [Sting] repo_param the url-sanitised-name of a given repo
122
+ # @param [String] ref the ref to link to.
69
123
  #
70
- # @return [String] HTML link to the given ref with class attached.
71
- def commit_ref(ref, repo_param)
72
- ref_class = ref.class.to_s.split("::")[1].to_s
73
- "<a class=\"ref #{ref_class}\" href=\"" + prefix_url("#{repo_param}/#{ref.name}") + "\">#{ref.name}</a>"
124
+ # @return [String] the HTML containing the link to the feed.
125
+ def atom_feed_url(repo_param, ref=nil)
126
+ ref.nil? ? prefix_url("#{repo_param}.atom") : prefix_url("#{repo_param}/#{ref}.atom")
74
127
  end
75
128
 
76
- # calls +Ginatra::Helpers#commit_ref+ for each ref in the commit
129
+ # Returns a HTML (+<ul>+) list of the files modified in a given commit.
77
130
  #
78
- # @see Ginatra::Helpers#commit_ref
131
+ # It includes classes for added/modified/deleted and also anchor links
132
+ # to the diffs for further down the page.
79
133
  #
80
- # @param [Grit::Commit] commit grit commit object
81
- # @param [String] repo_param the url-sanitised-name for the repo
82
- # (for the link path)
134
+ # @param [Rugged::Commit] commit the commit you want the list of files for
83
135
  #
84
- # @return [String] HTML containing all the ref links
85
- def commit_refs(commit, repo_param)
86
- commit.refs.map{ |r| commit_ref(r, repo_param) }.join("\n")
136
+ # @return [String] a +<ul>+ with lots of +<li>+ children.
137
+ def file_listing(diff)
138
+ list = []
139
+ diff.deltas.each_with_index do |delta, index|
140
+ if delta.deleted?
141
+ list << "<li class='deleted'><span class='icon-remove' title='deleted'></span> <a href='#file-#{index + 1}'>#{delta.new_file[:path]}</a></li>"
142
+ elsif delta.added?
143
+ list << "<li class='added'><span class='icon-ok' title='added'></span> <a href='#file-#{index + 1}'>#{delta.new_file[:path]}</a></li>"
144
+ elsif delta.modified?
145
+ list << "<li class='changed'><span class='icon-edit' title='modified'></span> <a href='#file-#{index + 1}'>#{delta.new_file[:path]}</a></li>"
146
+ end
147
+ end
148
+ "<ul class='unstyled'>#{list.join}</ul>"
87
149
  end
88
150
 
89
- # returns a string including the link to download a certain
90
- # tree of the repo
151
+ # Highlights commit diff
91
152
  #
92
- # @param [Grit::Tree] tree the tree you want an archive link for
93
- # @param [String] repo_param the url-sanitised-name of the repo
94
- # (for the link path)
153
+ # @param [Rugged::Hunk] diff hunk for highlighting
95
154
  #
96
- # @return [String] the HTML link to the archive.
97
- def archive_link(tree, repo_param)
98
- "<a class=\"download\" href=\"" + prefix_url("#{repo_param}/archive/#{tree.id}.tar.gz") + "\" title=\"Download a tar.gz snapshot of this Tree\">Download Archive</a>"
99
- end
155
+ # @return [String] highlighted HTML.code
156
+ def highlight_diff(hunk)
157
+ lines = []
158
+ lines << hunk.header
100
159
 
101
- # returns a string including the link to download a patch for a certain
102
- # commit to the repo
103
- #
104
- # @param [Grit::Commit] commit the commit you want a patch for
105
- # @param [String] repo_param the url-sanitised name for the repo
106
- # (for the link path)
107
- #
108
- # @return [String] the HTML link to the patch
109
- def patch_link(commit, repo_param)
110
- "<a class=\"download\" href=\"" + prefix_url("#{repo_param}/commit/#{commit.id}.patch") + "\" title=\"Download a patch file of this Commit\">Download Patch</a>"
160
+ hunk.each_line do |line|
161
+ if line.context?
162
+ lines << " #{line.content}"
163
+ elsif line.deletion?
164
+ lines << "- #{line.content}"
165
+ elsif line.addition?
166
+ lines << "+ #{line.content}"
167
+ end
168
+ end
169
+
170
+ formatter = Rouge::Formatters::HTML.new
171
+ lexer = Rouge::Lexers::Diff.new
172
+
173
+ source = lines.join
174
+ encoding = source.encoding
175
+ source = source.force_encoding(Encoding::UTF_8)
176
+
177
+ hd = formatter.format lexer.lex(source)
178
+ hd.force_encoding encoding
111
179
  end
112
180
 
113
- # returns a HTML (+<ul>+) list of the files altered in a given commit.
114
- #
115
- # It includes classes for added/altered/deleted and also anchor links
116
- # to the diffs for further down the page.
181
+ # Highlights blob source
117
182
  #
118
- # @param [Grit::Commit] commit the commit you want the list of files for
183
+ # @param [Rugged::Blob] blob to highlight source
119
184
  #
120
- # @return [String] a +<ul>+ with lots of +<li>+ children.
121
- def file_listing(commit)
122
- # The only reason this doesn't work 100% of the time is because grit doesn't :/
123
- # if i find a fix, it'll go upstream :D
124
- count = 0
125
- out = commit.diffs.map do |diff|
126
- count = count + 1
127
- if diff.deleted_file
128
- %(<li class='file_rm'><a href='#file_#{count}'>#{diff.a_path}</a></li>)
129
- else
130
- cla = diff.new_file ? "add" : "diff"
131
- %(<li class='file_#{cla}'><a href='#file_#{count}'>#{diff.a_path}</a></li>)
132
- end
185
+ # @return [String] highlighted HTML.code
186
+ def highlight_source(source, filename='')
187
+ source = source.force_encoding(Encoding::UTF_8)
188
+ formatter = Rouge::Formatters::HTML.new(line_numbers: true, wrap: false)
189
+ lexer = Rouge::Lexer.guess_by_filename(filename)
190
+
191
+ if lexer == Rouge::Lexers::PlainText
192
+ lexer = Rouge::Lexer.guess_by_source(source) || Rouge::Lexers::PlainText
133
193
  end
134
- "<ul id='files'>#{out.join}</ul>"
194
+
195
+ formatter.format lexer.lex(source)
135
196
  end
136
197
 
137
198
  # Formats the text to remove multiple spaces and newlines, and then inserts
138
199
  # HTML linebreaks.
139
200
  #
140
- # Stolen from rails: ActionView::Helpers::TextHelper#simple_format
141
- # and simplified to just use <p> tags without any options, then modified
201
+ # Borrowed from Rails: ActionView::Helpers::TextHelper#simple_format
202
+ # and simplified to just use <p> tags without any options, then modified
142
203
  # more later.
143
204
  #
144
205
  # @param [String] text the text you want formatted
145
- #
206
+ #
146
207
  # @return [String] the formatted text
147
208
  def simple_format(text)
148
209
  text.gsub!(/ +/, " ")
@@ -151,47 +212,16 @@ module Ginatra
151
212
  text
152
213
  end
153
214
 
154
- # Cleans up the particularly volatile parts of HTML
155
- # and replaces them with their entities. Replaces the following
156
- # characters:
157
- # - &
158
- # - >
159
- # - <
160
- # - '
161
- #
162
- # If you are using this with #simple_format, do not forget to call
163
- # this one first, then put in unsanitised linebreaks. The other way around
164
- # is full of fail.
165
- #
166
- # stolen from rails: ERB::Util
167
- #
168
- # @see Ginatra::Helpers#simple_format
169
- #
170
- # @param [#to_s] clean_me the object to clean.
171
- #
172
- # @return [String] the cleaned html text.
173
- def html_escape(clean_me)
174
- clean_me.to_s.gsub(/[&"<>]/) do |special|
175
- { '&' => '&amp;',
176
- '>' => '&gt;',
177
- '<' => '&lt;',
178
- '"' => '&quot;' }[special]
179
- end
180
- end
181
- alias :h :html_escape
182
-
183
215
  # Truncates a given text to a certain number of letters, including a special ending if needed.
184
216
  #
185
- # Stolen and bastardised from rails
186
- #
187
217
  # @param [String] text the text to truncate
188
218
  # @option options [Integer] :length (30) the length you want the output string
189
219
  # @option options [String] :omission ("...") the string to show an omission.
190
220
  #
191
221
  # @return [String] the truncated text.
192
222
  def truncate(text, options={})
193
- options[:length] ||= 30
194
- options[:omission] ||= "..."
223
+ options[:length] ||= 30
224
+ options[:omission] ||= "..."
195
225
 
196
226
  if text
197
227
  l = options[:length] - options[:omission].length
@@ -203,32 +233,17 @@ module Ginatra
203
233
 
204
234
  # Returns the rfc representation of a date, for use in the atom feeds.
205
235
  #
206
- # stolen from Marley
207
- #
208
236
  # @param [DateTime] datetime the date to format
209
237
  # @return [String] the formatted datetime
210
238
  def rfc_date(datetime)
211
239
  datetime.strftime("%Y-%m-%dT%H:%M:%SZ") # 2003-12-13T18:30:02Z
212
240
  end
213
241
 
214
- # Returns the Hostname of the given install.
215
- # used in the atom feeds.
242
+ # Returns the Hostname of the given install, for use in the atom feeds.
216
243
  #
217
- # stolen from Marley
218
- #
219
244
  # @return [String] the hostname of the server. Respects HTTP-X-Forwarded-For
220
245
  def hostname
221
246
  (request.env['HTTP_X_FORWARDED_SERVER'] =~ /[a-z]*/) ? request.env['HTTP_X_FORWARDED_SERVER'] : request.env['HTTP_HOST']
222
247
  end
223
-
224
- # Spits out a HTML link to the atom feed for a given ref of a given repo
225
- #
226
- # @param [Sting] repo_param the url-sanitised-name of a given repo
227
- # @param [String] ref the ref to link to.
228
- #
229
- # @return [String] the HTML containing the link to the feed.
230
- def atom_feed_link(repo_param, ref=nil)
231
- "<a href=\"" + prefix_url("#{repo_param}#{"/#{ref}" if !ref.nil?}.atom") + "\" title=\"Atom Feed\" class=\"atom\">Feed</a>"
232
- end
233
248
  end
234
249
  end