yard_ghurt 1.2.0 → 1.2.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -2
- data/Gemfile +0 -18
- data/README.md +28 -15
- data/Rakefile +24 -37
- data/bin/yard_ghurt +5 -16
- data/lib/yard_ghurt.rb +22 -34
- data/lib/yard_ghurt/anchor_links.rb +98 -107
- data/lib/yard_ghurt/gfm_fix_task.rb +210 -208
- data/lib/yard_ghurt/ghp_sync_task.rb +46 -56
- data/lib/yard_ghurt/util.rb +83 -33
- data/lib/yard_ghurt/version.rb +4 -16
- data/yard_ghurt.gemspec +18 -29
- metadata +23 -23
@@ -1,23 +1,11 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
# encoding: UTF-8
|
3
2
|
# frozen_string_literal: true
|
4
3
|
|
5
4
|
#--
|
6
5
|
# This file is part of YardGhurt.
|
7
|
-
# Copyright (c) 2019 Jonathan Bradley Whited
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# it under the terms of the GNU Lesser General Public License as published by
|
11
|
-
# the Free Software Foundation, either version 3 of the License, or
|
12
|
-
# (at your option) any later version.
|
13
|
-
#
|
14
|
-
# YardGhurt is distributed in the hope that it will be useful,
|
15
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
-
# GNU Lesser General Public License for more details.
|
18
|
-
#
|
19
|
-
# You should have received a copy of the GNU Lesser General Public License
|
20
|
-
# along with YardGhurt. If not, see <https://www.gnu.org/licenses/>.
|
6
|
+
# Copyright (c) 2019-2021 Jonathan Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
21
9
|
#++
|
22
10
|
|
23
11
|
|
@@ -30,13 +18,13 @@ require 'yard_ghurt/util'
|
|
30
18
|
module YardGhurt
|
31
19
|
###
|
32
20
|
# Sync YARDoc to a local GitHub Pages repo (uses +rsync+ by default).
|
33
|
-
#
|
21
|
+
#
|
34
22
|
# @example What I Use
|
35
23
|
# YardGhurt::GHPSyncTask.new() do |task|
|
36
24
|
# task.ghp_dir = '../esotericpig.github.io/docs/yard_ghurt/yardoc'
|
37
25
|
# task.sync_args << '--delete-after'
|
38
26
|
# end
|
39
|
-
#
|
27
|
+
#
|
40
28
|
# @example Using All Options
|
41
29
|
# # Execute: rake ghp_doc[false,'Ruby']
|
42
30
|
# YardGhurt::GHPSyncTask.new(:ghp_doc) do |task|
|
@@ -48,68 +36,70 @@ module YardGhurt
|
|
48
36
|
# task.strict = true # Fail if doc_dir doesn't exist
|
49
37
|
# task.sync_args << '--delete-after'
|
50
38
|
# task.sync_cmd = '/usr/bin/rsync'
|
51
|
-
#
|
39
|
+
#
|
52
40
|
# task.before = Proc.new() {|task,args| puts "Hi, #{args.name}!"}
|
53
41
|
# task.after = Proc.new() {|task,args| puts "Goodbye, #{args.name}!"}
|
54
42
|
# end
|
55
|
-
#
|
56
|
-
# @author Jonathan Bradley Whited
|
43
|
+
#
|
44
|
+
# @author Jonathan Bradley Whited
|
57
45
|
# @since 1.1.0
|
58
46
|
###
|
59
47
|
class GHPSyncTask < Rake::TaskLib
|
60
48
|
# @return [Proc,nil] the Proc ( +respond_to?(:call)+ ) to call at the end of this task or +nil+;
|
61
49
|
# default: +nil+
|
62
50
|
attr_accessor :after
|
63
|
-
|
51
|
+
|
64
52
|
# @note +:deploy+ will be added no matter what (cannot be deleted)
|
65
|
-
#
|
53
|
+
#
|
66
54
|
# @return [Array<Symbol>,Symbol] the custom arg(s) for this task; default: +[:deploy]+
|
67
55
|
attr_accessor :arg_names
|
68
|
-
|
56
|
+
|
69
57
|
# @return [Proc,nil] the Proc ( +respond_to?(:call)+ ) to call at the beginning of this task or +nil+;
|
70
58
|
# default: +nil+
|
71
59
|
attr_accessor :before
|
72
|
-
|
60
|
+
|
73
61
|
# @example
|
74
62
|
# task.deps = :yard
|
75
63
|
# # or...
|
76
64
|
# task.deps = [:yard,:yard_gfm_fix]
|
77
|
-
#
|
65
|
+
#
|
78
66
|
# @return [Array<Symbol>,Symbol] the custom dependencies for this task; default: +[]+
|
79
67
|
attr_accessor :deps
|
80
|
-
|
68
|
+
|
81
69
|
# @return [String] the description of this task (customizable)
|
82
70
|
attr_accessor :description
|
83
|
-
|
71
|
+
|
84
72
|
# @return [String] the source directory of generated YARDoc files; default: +doc+
|
85
73
|
attr_accessor :doc_dir
|
86
|
-
|
74
|
+
|
87
75
|
# @note You must set this, else an error is thrown.
|
88
|
-
#
|
76
|
+
#
|
89
77
|
# @return [String] the destination directory to sync {doc_dir} to
|
90
78
|
attr_accessor :ghp_dir
|
91
|
-
|
79
|
+
|
92
80
|
# @return [String] the name of this task (customizable); default: +yard_ghp_sync+
|
93
81
|
attr_accessor :name
|
94
|
-
|
82
|
+
|
95
83
|
# If you want to use a non-local {doc_dir} (a remote host), set this to +false+.
|
96
|
-
#
|
84
|
+
#
|
97
85
|
# @return [true,false] whether to throw an error if {doc_dir} does not exist; default: +true+
|
98
86
|
attr_accessor :strict
|
99
|
-
|
87
|
+
|
100
88
|
# @note You should pass in multi-args separately: +['--exclude','*~']+
|
101
89
|
# @note You should not single/double quote the args; +['"*~"']+ is unnecessary.
|
102
|
-
#
|
90
|
+
#
|
103
91
|
# @return [Array<String>] the args to pass to the {sync_cmd}; default: +['-ahv','--progress']+
|
104
92
|
attr_accessor :sync_args
|
105
|
-
|
93
|
+
|
106
94
|
# @return [String] the sync command to use on the command line; default: +rsync+
|
107
95
|
attr_accessor :sync_cmd
|
108
|
-
|
96
|
+
|
109
97
|
alias_method :strict?,:strict
|
110
|
-
|
98
|
+
|
111
99
|
# @param name [Symbol] the name of this task to use on the command line with +rake+
|
112
100
|
def initialize(name=:yard_ghp_sync)
|
101
|
+
super()
|
102
|
+
|
113
103
|
@after = nil
|
114
104
|
@arg_names = []
|
115
105
|
@before = nil
|
@@ -121,22 +111,22 @@ module YardGhurt
|
|
121
111
|
@strict = true
|
122
112
|
@sync_args = ['-ahv','--progress']
|
123
113
|
@sync_cmd = 'rsync'
|
124
|
-
|
125
|
-
yield self if block_given?
|
126
|
-
define
|
114
|
+
|
115
|
+
yield self if block_given?
|
116
|
+
define
|
127
117
|
end
|
128
|
-
|
118
|
+
|
129
119
|
# Define the Rake task and description using the instance variables.
|
130
|
-
def define
|
120
|
+
def define
|
131
121
|
@arg_names = *@arg_names
|
132
122
|
@arg_names.unshift(:deploy) unless @arg_names.include?(:deploy)
|
133
|
-
|
123
|
+
|
134
124
|
desc @description
|
135
125
|
task @name,@arg_names => Array(@deps) do |task,args|
|
136
126
|
deploy = Util.to_bool(args.deploy)
|
137
|
-
|
127
|
+
|
138
128
|
@before.call(self,args) if @before.respond_to?(:call)
|
139
|
-
|
129
|
+
|
140
130
|
# Without these checks, sh raises some pretty cryptic errors.
|
141
131
|
if @strict
|
142
132
|
# If you want to use a non-local dir, set strict to false.
|
@@ -145,38 +135,38 @@ module YardGhurt
|
|
145
135
|
end
|
146
136
|
end
|
147
137
|
# Do not check if ghp_dir exists because rsync may create it.
|
148
|
-
if @ghp_dir.nil?
|
138
|
+
if @ghp_dir.nil? || @ghp_dir.to_s.strip.empty?
|
149
139
|
raise ArgumentError,"#{self.class}.ghp_dir must be set"
|
150
140
|
end
|
151
|
-
|
141
|
+
|
152
142
|
sh(*build_sh_cmd(deploy))
|
153
|
-
|
143
|
+
|
154
144
|
if !deploy
|
155
145
|
puts
|
156
146
|
puts %Q(Execute "rake #{@name}[true]" for actually deploying (not a dry-run))
|
157
147
|
end
|
158
|
-
|
148
|
+
|
159
149
|
@after.call(self,args) if @after.respond_to?(:call)
|
160
150
|
end
|
161
|
-
|
151
|
+
|
162
152
|
return self
|
163
153
|
end
|
164
|
-
|
154
|
+
|
165
155
|
# Build the sync command to use on the command line.
|
166
|
-
#
|
156
|
+
#
|
167
157
|
# @param deploy [true,false] whether to actually deploy (+true+) or to run a dry-run (+false+)
|
168
|
-
#
|
158
|
+
#
|
169
159
|
# @return [Array<String>] the sync command and its args
|
170
160
|
def build_sh_cmd(deploy)
|
171
161
|
sh_cmd = [@sync_cmd]
|
172
|
-
|
162
|
+
|
173
163
|
sh_cmd << '--dry-run' unless deploy
|
174
164
|
sh_cmd.push(*@sync_args)
|
175
|
-
|
165
|
+
|
176
166
|
# File.join() to add a trailing '/' if not present
|
177
167
|
sh_cmd << File.join(@doc_dir,'')
|
178
168
|
sh_cmd << File.join(@ghp_dir,'')
|
179
|
-
|
169
|
+
|
180
170
|
return sh_cmd
|
181
171
|
end
|
182
172
|
end
|
data/lib/yard_ghurt/util.rb
CHANGED
@@ -1,23 +1,11 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
# encoding: UTF-8
|
3
2
|
# frozen_string_literal: true
|
4
3
|
|
5
4
|
#--
|
6
5
|
# This file is part of YardGhurt.
|
7
|
-
# Copyright (c) 2019 Jonathan Bradley Whited
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# it under the terms of the GNU Lesser General Public License as published by
|
11
|
-
# the Free Software Foundation, either version 3 of the License, or
|
12
|
-
# (at your option) any later version.
|
13
|
-
#
|
14
|
-
# YardGhurt is distributed in the hope that it will be useful,
|
15
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
-
# GNU Lesser General Public License for more details.
|
18
|
-
#
|
19
|
-
# You should have received a copy of the GNU Lesser General Public License
|
20
|
-
# along with YardGhurt. If not, see <https://www.gnu.org/licenses/>.
|
6
|
+
# Copyright (c) 2019-2021 Jonathan Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
21
9
|
#++
|
22
10
|
|
23
11
|
|
@@ -26,56 +14,118 @@ module YardGhurt
|
|
26
14
|
# Utility methods in a separate module/mixin,
|
27
15
|
# so that a programmer can require/load a sole task:
|
28
16
|
# require 'yard_ghurt/gfm_fix_task'
|
29
|
-
#
|
17
|
+
#
|
30
18
|
# Else, programmers would be required to always require/load the entire +yard_ghurt+ module:
|
31
19
|
# require 'yard_ghurt'
|
32
|
-
#
|
20
|
+
#
|
33
21
|
# All internal code should use this module.
|
34
|
-
#
|
22
|
+
#
|
35
23
|
# External code can either use this module or {YardGhurt},
|
36
24
|
# which includes this module as a mixin.
|
37
|
-
#
|
38
|
-
# @author Jonathan Bradley Whited
|
25
|
+
#
|
26
|
+
# @author Jonathan Bradley Whited
|
39
27
|
# @since 1.0.0
|
40
28
|
###
|
41
29
|
module Util
|
42
30
|
# @return [Array<String>] the lower-case Strings that will equal to +true+
|
43
|
-
TRUE_BOOLS = [
|
44
|
-
|
31
|
+
TRUE_BOOLS = %w[ 1 on t true y yes ].freeze
|
32
|
+
|
33
|
+
# @return a very flexible (non-strict) Semantic Versioning regex, ignoring pre-release/build-metadata
|
34
|
+
# @since 1.2.1
|
35
|
+
SEM_VER_REGEX = /(?<major>\d+)(?:\.(?<minor>\d+))?(?:\.(?<patch>\d+))?/.freeze
|
36
|
+
|
45
37
|
# If +include Util+ is called, extend {ClassMethods}.
|
46
|
-
#
|
38
|
+
#
|
47
39
|
# @param mod [Module] the module to extend
|
48
40
|
def self.included(mod)
|
49
41
|
mod.extend ClassMethods
|
50
42
|
end
|
51
|
-
|
43
|
+
|
52
44
|
module ClassMethods
|
45
|
+
@yard_sem_ver = nil
|
46
|
+
|
53
47
|
# If +filename+ exists, delete it, and if +output+ is +true+, log it to stdout.
|
54
|
-
#
|
48
|
+
#
|
55
49
|
# @param filename [String] the file to remove
|
56
50
|
# @param output [true,false] whether to log it to stdout
|
57
51
|
def rm_exist(filename,output=true)
|
58
52
|
return unless File.exist?(filename)
|
59
|
-
|
53
|
+
|
60
54
|
puts "[#{filename}]: - Deleted" if output
|
61
55
|
File.delete(filename)
|
62
56
|
end
|
63
|
-
|
57
|
+
|
64
58
|
# Convert +str+ to +true+ or +false+.
|
65
|
-
#
|
59
|
+
#
|
66
60
|
# Even if +str+ is not a String, +to_s()+ will be called, so should be safe.
|
67
|
-
#
|
61
|
+
#
|
68
62
|
# @param str [String,Object] the String (or Object) to convert
|
69
|
-
#
|
63
|
+
#
|
70
64
|
# @return [true,false] the boolean value of +str+
|
71
|
-
#
|
65
|
+
#
|
72
66
|
# @see TRUE_BOOLS
|
73
67
|
# @see GHPSyncTask#arg_names
|
74
68
|
def to_bool(str)
|
75
|
-
return TRUE_BOOLS.include?(str.to_s
|
69
|
+
return TRUE_BOOLS.include?(str.to_s.downcase)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Parse +str+ as a non-strict Semantic Version:
|
73
|
+
# \d+.\d+.\d+
|
74
|
+
#
|
75
|
+
# Unlike the specification, minor and patch are optional.
|
76
|
+
# Also, pre-release and build metadata are ignored.
|
77
|
+
# This is used for checking the YARD version internally,
|
78
|
+
# so needs to be very flexible.
|
79
|
+
#
|
80
|
+
# @param str [String,Object] the object to parse; +to_s()+ will be called on it
|
81
|
+
# @return [Hash] the Semantic Version parts: +{:major, :minor, :patch}+
|
82
|
+
# defaults all values to +0+ if the version cannot be parsed
|
83
|
+
# @see SEM_VER_REGEX
|
84
|
+
# @see #yard_sem_ver
|
85
|
+
# @since 1.2.1
|
86
|
+
def parse_sem_ver(str)
|
87
|
+
sem_ver = {
|
88
|
+
major: 0,minor: 0,patch: 0,
|
89
|
+
}
|
90
|
+
|
91
|
+
match = SEM_VER_REGEX.match(str.to_s.gsub(/\s+/u,''))
|
92
|
+
|
93
|
+
return sem_ver unless match
|
94
|
+
|
95
|
+
sem_ver[:major] = match[:major].to_i
|
96
|
+
sem_ver[:minor] = match[:minor].to_i unless match[:minor].nil?
|
97
|
+
sem_ver[:patch] = match[:patch].to_i unless match[:patch].nil?
|
98
|
+
|
99
|
+
return sem_ver
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns YARD's version as a +Hash+ of parts:
|
103
|
+
# { major: 0, minor: 0, patch: 0 }
|
104
|
+
#
|
105
|
+
# If the version can not be parsed, it will return the exact
|
106
|
+
# same +Hash+ as above with all values to +0+.
|
107
|
+
#
|
108
|
+
# On initial call, it will parse it and store it.
|
109
|
+
# On subsequent calls, it will return the stored value.
|
110
|
+
#
|
111
|
+
# @return [Hash] YARD's version parts
|
112
|
+
# @see parse_sem_ver
|
113
|
+
# @since 1.2.1
|
114
|
+
def yard_sem_ver
|
115
|
+
return @yard_sem_ver unless @yard_sem_ver.nil?
|
116
|
+
|
117
|
+
require 'yard'
|
118
|
+
|
119
|
+
if defined?(YARD::VERSION)
|
120
|
+
ver = YARD::VERSION
|
121
|
+
else
|
122
|
+
ver = ''
|
123
|
+
end
|
124
|
+
|
125
|
+
return(@yard_sem_ver = parse_sem_ver(ver))
|
76
126
|
end
|
77
127
|
end
|
78
|
-
|
128
|
+
|
79
129
|
extend ClassMethods
|
80
130
|
end
|
81
131
|
end
|
data/lib/yard_ghurt/version.rb
CHANGED
@@ -1,26 +1,14 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
# encoding: UTF-8
|
3
2
|
# frozen_string_literal: true
|
4
3
|
|
5
4
|
#--
|
6
5
|
# This file is part of YardGhurt.
|
7
|
-
# Copyright (c) 2019 Jonathan Bradley Whited
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# it under the terms of the GNU Lesser General Public License as published by
|
11
|
-
# the Free Software Foundation, either version 3 of the License, or
|
12
|
-
# (at your option) any later version.
|
13
|
-
#
|
14
|
-
# YardGhurt is distributed in the hope that it will be useful,
|
15
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
-
# GNU Lesser General Public License for more details.
|
18
|
-
#
|
19
|
-
# You should have received a copy of the GNU Lesser General Public License
|
20
|
-
# along with YardGhurt. If not, see <https://www.gnu.org/licenses/>.
|
6
|
+
# Copyright (c) 2019-2021 Jonathan Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
21
9
|
#++
|
22
10
|
|
23
11
|
|
24
12
|
module YardGhurt
|
25
|
-
VERSION = '1.2.
|
13
|
+
VERSION = '1.2.1'
|
26
14
|
end
|
data/yard_ghurt.gemspec
CHANGED
@@ -3,20 +3,9 @@
|
|
3
3
|
|
4
4
|
#--
|
5
5
|
# This file is part of YardGhurt.
|
6
|
-
# Copyright (c) 2019-
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# it under the terms of the GNU Lesser General Public License as published by
|
10
|
-
# the Free Software Foundation, either version 3 of the License, or
|
11
|
-
# (at your option) any later version.
|
12
|
-
#
|
13
|
-
# YardGhurt is distributed in the hope that it will be useful,
|
14
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
-
# GNU Lesser General Public License for more details.
|
17
|
-
#
|
18
|
-
# You should have received a copy of the GNU Lesser General Public License
|
19
|
-
# along with YardGhurt. If not, see <https://www.gnu.org/licenses/>.
|
6
|
+
# Copyright (c) 2019-2021 Jonathan Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
20
9
|
#++
|
21
10
|
|
22
11
|
|
@@ -25,16 +14,16 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
25
14
|
|
26
15
|
require 'yard_ghurt/version'
|
27
16
|
|
28
|
-
Gem::Specification.new
|
17
|
+
Gem::Specification.new do |spec|
|
29
18
|
spec.name = 'yard_ghurt'
|
30
19
|
spec.version = YardGhurt::VERSION
|
31
|
-
spec.authors = ['Jonathan Bradley Whited
|
32
|
-
spec.email = ['
|
20
|
+
spec.authors = ['Jonathan Bradley Whited']
|
21
|
+
spec.email = ['code@esotericpig.com']
|
33
22
|
spec.licenses = ['LGPL-3.0-or-later']
|
34
23
|
spec.homepage = 'https://github.com/esotericpig/yard_ghurt'
|
35
24
|
spec.summary = 'YARDoc GitHub Rake Tasks'
|
36
25
|
spec.description = "#{spec.summary}. Fix GitHub Flavored Markdown (GFM) files."
|
37
|
-
|
26
|
+
|
38
27
|
spec.metadata = {
|
39
28
|
'bug_tracker_uri' => 'https://github.com/esotericpig/yard_ghurt/issues',
|
40
29
|
'changelog_uri' => 'https://github.com/esotericpig/yard_ghurt/blob/master/CHANGELOG.md',
|
@@ -42,23 +31,23 @@ Gem::Specification.new() do |spec|
|
|
42
31
|
'homepage_uri' => 'https://github.com/esotericpig/yard_ghurt',
|
43
32
|
'source_code_uri' => 'https://github.com/esotericpig/yard_ghurt'
|
44
33
|
}
|
45
|
-
|
34
|
+
|
46
35
|
spec.require_paths = ['lib']
|
47
36
|
spec.bindir = 'bin'
|
48
37
|
spec.executables = [spec.name]
|
49
|
-
|
38
|
+
|
50
39
|
spec.files = Dir.glob(File.join("{#{spec.require_paths.join(',')}}",'**','*.{erb,rb}')) +
|
51
40
|
Dir.glob(File.join(spec.bindir,'**',"{#{spec.executables.join(',')}}")) +
|
52
41
|
Dir.glob(File.join('{test,yard}','**','*.{erb,rb}')) +
|
53
|
-
%W
|
54
|
-
%w
|
55
|
-
|
42
|
+
%W[ Gemfile #{spec.name}.gemspec Rakefile ] +
|
43
|
+
%w[ CHANGELOG.md LICENSE.txt README.md ]
|
44
|
+
|
56
45
|
spec.required_ruby_version = '>= 2.1.10'
|
57
|
-
|
58
|
-
spec.add_runtime_dependency 'rake'
|
59
|
-
|
60
|
-
|
61
|
-
spec.add_development_dependency '
|
46
|
+
|
47
|
+
spec.add_runtime_dependency 'rake' # 13.0.3
|
48
|
+
spec.add_runtime_dependency 'yard' # 0.9.26, 0.9.24 (diff)
|
49
|
+
|
50
|
+
spec.add_development_dependency 'bundler' ,'~> 2.2'
|
51
|
+
spec.add_development_dependency 'rdoc' ,'~> 6.3' # For RDoc for YARD (*.rb)
|
62
52
|
spec.add_development_dependency 'redcarpet','~> 3.5' # For Markdown for YARD (*.md)
|
63
|
-
spec.add_development_dependency 'yard' ,'~> 0.9'
|
64
53
|
end
|