yard-contracts 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +4 -2
- data/lib/yard-contracts.rb +1 -4
- data/lib/yard-contracts/contract_handler.rb +58 -31
- data/lib/yard-contracts/formatters.rb +30 -24
- data/lib/yard-contracts/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51d85c2afe33dd7f5aa247c1731704b2b78123bc
|
4
|
+
data.tar.gz: 81c3ea5834a91fd1af549dae5d849b69218b2c5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a67e1b2c71f0343c07b17a796b2d8eac4928eb45976afdf31ea61267e430f6a859601a2aad286e0cca8758458cfc84552c107dd6e1a5869b0cb284854a94ef5
|
7
|
+
data.tar.gz: 507927641c2f838c3ec02aaf471bc4377ceae251a0cb137b59ae8f8633e2626417aa6e8c7071cd035a466efea71c41fe2104a3461437e6a402799014e0f712c5
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# yard-contracts
|
2
2
|
|
3
|
-
[![Build Status](https://travis-ci.org/sfcgeorge/yard-contracts.svg?branch=master)](https://travis-ci.org/sfcgeorge/yard-contracts)
|
4
3
|
[![Gem Version](https://badge.fury.io/rb/yard-contracts.svg)](http://badge.fury.io/rb/yard-contracts)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/sfcgeorge/yard-contracts/badges/gpa.svg)](https://codeclimate.com/github/sfcgeorge/yard-contracts)
|
5
|
+
[![Build Status](https://travis-ci.org/sfcgeorge/yard-contracts.svg?branch=master)](https://travis-ci.org/sfcgeorge/yard-contracts)
|
6
|
+
[![Inline docs](http://inch-ci.org/github/sfcgeorge/yard-contracts.svg?branch=master)](http://inch-ci.org/github/sfcgeorge/yard-contracts)
|
5
7
|
[![Join the chat at https://gitter.im/egonSchiele/contracts.ruby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/egonSchiele/contracts.ruby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
6
8
|
|
7
|
-
yard-contracts is a YARD plugin that works with the fantastic Contracts gem to automatically document types and descriptions of parameters in your method signatures, saving time, making your code concise and keeping your documentation consistent.
|
9
|
+
yard-contracts is a YARD plugin that works with the fantastic [Contracts](https://github.com/egonSchiele/contracts.ruby) gem to automatically document types and descriptions of parameters in your method signatures, saving time, making your code concise and keeping your documentation consistent.
|
8
10
|
|
9
11
|
Have you ever got fed up of coding validations, writing error messages and then documenting those things? All this duplication and boilerplate code has always bugged me. Contracts solves the validations and error messages part already, turning many lines of repetitive code into 1 terse readable one. This extension now solves the documentation part making documentation automatically say the same as your validations.
|
10
12
|
|
data/lib/yard-contracts.rb
CHANGED
@@ -8,12 +8,13 @@ require 'yard'
|
|
8
8
|
require 'contracts/builtin_contracts'
|
9
9
|
require 'yard-contracts/formatters'
|
10
10
|
|
11
|
-
# Run the plugin handler by supplying it to yard with the --plugin flag
|
11
|
+
# Run the plugin handler by supplying it to yard with the --plugin flag
|
12
12
|
#
|
13
|
-
#
|
13
|
+
# @example
|
14
|
+
# bundle exec yardoc --plugin contracts
|
14
15
|
class ContractHandler < YARD::Handlers::Ruby::Base
|
15
16
|
handles method_call(:Contract)
|
16
|
-
namespace_only #only match
|
17
|
+
namespace_only # only match calls inside a namespace not inside a method
|
17
18
|
|
18
19
|
def process
|
19
20
|
# statement is a YARD attribute, subclassing YARD::Parser::Ruby::AstNode
|
@@ -27,7 +28,7 @@ class ContractHandler < YARD::Handlers::Ruby::Base
|
|
27
28
|
# Note: this won't document dynamicly defined methods.
|
28
29
|
parent = statement.parent
|
29
30
|
contract_last_line = statement.line_range.last
|
30
|
-
#YARD::Parser::Ruby::MethodDefinitionNode
|
31
|
+
# YARD::Parser::Ruby::MethodDefinitionNode
|
31
32
|
def_method_ast = parent.traverse do |node|
|
32
33
|
# Find the first def statement that comes after the contract we're on
|
33
34
|
break node if node.line > contract_last_line && node.def?
|
@@ -37,48 +38,74 @@ class ContractHandler < YARD::Handlers::Ruby::Base
|
|
37
38
|
## TODO: What about module methods? Probably broken.
|
38
39
|
scope = def_method_ast.source.match(/ self\./) ? :class : :instance
|
39
40
|
name = def_method_ast.method_name true
|
40
|
-
params = def_method_ast.parameters #YARD::Parser::Ruby::ParameterNode
|
41
|
-
contracts = statement.parameters #YARD::Parser::Ruby::AstNode
|
41
|
+
params = def_method_ast.parameters # YARD::Parser::Ruby::ParameterNode
|
42
|
+
contracts = statement.parameters # YARD::Parser::Ruby::AstNode
|
42
43
|
|
43
44
|
ret = Contracts::Formatters::ParamContracts.new(params, contracts).return
|
44
45
|
params = Contracts::Formatters::ParamContracts.new(params, contracts).params
|
45
|
-
|
46
|
+
doc = YARD::DocstringParser.new.parse(statement.docstring).to_docstring
|
46
47
|
|
48
|
+
process_params(doc, params)
|
49
|
+
process_return(doc, ret)
|
50
|
+
|
51
|
+
# YARD hasn't got to the def method yet, so we create a stub of it with
|
52
|
+
# our docstring, when YARD gets to it properly it will fill in the rest.
|
53
|
+
YARD::CodeObjects::MethodObject.new(namespace, name, scope) do |o|
|
54
|
+
o.docstring = doc
|
55
|
+
end
|
56
|
+
# No `register()` it breaks stuff! Above implicit return value is enough.
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_params(doc, params)
|
60
|
+
merge_params(doc, params)
|
61
|
+
new_params(doc, params)
|
62
|
+
end
|
63
|
+
|
64
|
+
def merge_params(doc, params)
|
47
65
|
# Merge params into provided docstring otherwise there can be duplicates
|
48
|
-
|
49
|
-
param = params.find{ |t| t[0].to_s == tag.name.to_s }
|
50
|
-
|
51
|
-
|
52
|
-
tag.types ||= []
|
53
|
-
tag.types << param[1].inspect
|
54
|
-
tag.text = "#{param[2].empty? ? '' : "#{param[2]}. "}#{tag.text}"
|
55
|
-
end
|
66
|
+
doc.tags(:param).each do |tag|
|
67
|
+
next unless (param = params.find { |t| t[0].to_s == tag.name.to_s })
|
68
|
+
params.delete(param)
|
69
|
+
set_tag(tag, param[1], param[2])
|
56
70
|
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def new_params(doc, params)
|
57
74
|
# If the docstring didn't contain all of the params already add the rest
|
58
75
|
params.each do |param|
|
59
|
-
|
76
|
+
doc.add_tag(
|
60
77
|
YARD::Tags::Tag.new(:param, param[2].to_s, param[1].inspect, param[0])
|
61
78
|
)
|
62
79
|
end
|
80
|
+
end
|
63
81
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
tag
|
68
|
-
tag.types << ret[0].inspect
|
69
|
-
tag.text = "#{ret[1].empty? ? '' : "#{ret[1]}. "}#{tag.text}"
|
82
|
+
def process_return(doc, ret)
|
83
|
+
if (tag = doc.tag :return)
|
84
|
+
# Merge return into provided docstring otherwise there can be a duplicate
|
85
|
+
merge_return(tag, ret)
|
70
86
|
else
|
71
87
|
# If the docstring didn't contain a return already add it
|
72
|
-
|
73
|
-
YARD::Tags::Tag.new(:return, ret[1].to_s, ret[0].inspect)
|
74
|
-
)
|
88
|
+
new_return(doc, ret)
|
75
89
|
end
|
90
|
+
end
|
76
91
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
92
|
+
def merge_return(tag, ret)
|
93
|
+
set_tag(tag, ret[0], ret[1])
|
94
|
+
end
|
95
|
+
|
96
|
+
def new_return(doc, ret)
|
97
|
+
doc.add_tag(
|
98
|
+
YARD::Tags::Tag.new(:return, ret[1].to_s, ret[0].inspect)
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
def set_tag(tag, type, to_s)
|
103
|
+
tag.types ||= []
|
104
|
+
tag.types << type.inspect
|
105
|
+
tag.text = tag_text(to_s, tag.text)
|
106
|
+
end
|
107
|
+
|
108
|
+
def tag_text(to_s, text)
|
109
|
+
"#{to_s.empty? ? '' : "#{to_s}. "}#{text}"
|
83
110
|
end
|
84
111
|
end
|
@@ -5,7 +5,7 @@ module Contracts
|
|
5
5
|
module Formatters
|
6
6
|
# Used to format contracts for the `Expected:` field of error output.
|
7
7
|
class Expected
|
8
|
-
def initialize(contract, full=true)
|
8
|
+
def initialize(contract, full = true)
|
9
9
|
@contract, @full = contract, full
|
10
10
|
end
|
11
11
|
|
@@ -23,22 +23,22 @@ module Contracts
|
|
23
23
|
# Formats Hash contracts.
|
24
24
|
def hash_contract(hash)
|
25
25
|
@full = true
|
26
|
-
hash.inject({})
|
26
|
+
hash.inject({}) do |repr, (k, v)|
|
27
27
|
repr.merge(k => InspectWrapper.new(contract(v), @full))
|
28
|
-
|
28
|
+
end.inspect
|
29
29
|
end
|
30
30
|
|
31
31
|
# Formats Array contracts.
|
32
32
|
def array_contract(array)
|
33
33
|
@full = true
|
34
|
-
array.map{ |v| InspectWrapper.new(contract(v), @full) }.inspect
|
34
|
+
array.map { |v| InspectWrapper.new(contract(v), @full) }.inspect
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
# A wrapper class to produce correct inspect behaviour for different
|
39
39
|
# contract values - constants, Class contracts, instance contracts etc.
|
40
40
|
class InspectWrapper
|
41
|
-
def initialize(value, full=true)
|
41
|
+
def initialize(value, full = true)
|
42
42
|
@value, @full = value, full
|
43
43
|
end
|
44
44
|
|
@@ -51,7 +51,7 @@ module Contracts
|
|
51
51
|
return '' unless full?
|
52
52
|
return @value.inspect if empty_val?
|
53
53
|
return @value.to_s if plain?
|
54
|
-
return delim(@value.to_s) if
|
54
|
+
return delim(@value.to_s) if useful_to_s?
|
55
55
|
@value.inspect.gsub(/^Contracts::/, '')
|
56
56
|
end
|
57
57
|
|
@@ -65,14 +65,15 @@ module Contracts
|
|
65
65
|
end
|
66
66
|
|
67
67
|
private
|
68
|
+
|
68
69
|
def empty_val?
|
69
|
-
@value.nil? || @value ==
|
70
|
+
@value.nil? || @value == ''
|
70
71
|
end
|
71
72
|
|
72
73
|
def full?
|
73
74
|
@full ||
|
74
|
-
|
75
|
-
|
75
|
+
@value.is_a?(Hash) || @value.is_a?(Array) ||
|
76
|
+
(!plain? && useful_to_s?)
|
76
77
|
end
|
77
78
|
|
78
79
|
def plain?
|
@@ -80,10 +81,14 @@ module Contracts
|
|
80
81
|
!@value.is_a?(CallableClass) && @value.class != Class
|
81
82
|
end
|
82
83
|
|
83
|
-
def
|
84
|
+
def useful_to_s?
|
84
85
|
# Useless to_s value or no custom to_s behavious defined
|
85
|
-
|
86
|
-
|
86
|
+
@value.to_s != '' &&
|
87
|
+
if @value.class == Class # It's a class contract
|
88
|
+
@value.to_s != @value.name
|
89
|
+
else # It's an instance contract
|
90
|
+
!@value.to_s.match(/#\<\w+:.+\>/)
|
91
|
+
end
|
87
92
|
end
|
88
93
|
end
|
89
94
|
|
@@ -95,7 +100,7 @@ module Contracts
|
|
95
100
|
def to_a
|
96
101
|
types = []
|
97
102
|
@types.each_with_index do |type, i|
|
98
|
-
if i == @types.length-1
|
103
|
+
if i == @types.length - 1
|
99
104
|
# Get the param out of the `param => result` part
|
100
105
|
types << [type.first.first.source, type.first.first]
|
101
106
|
else
|
@@ -118,8 +123,8 @@ module Contracts
|
|
118
123
|
|
119
124
|
def to_a
|
120
125
|
params = []
|
121
|
-
@params.
|
122
|
-
#YARD::Parser::Ruby::AstNode
|
126
|
+
@params.each do |param|
|
127
|
+
# YARD::Parser::Ruby::AstNode
|
123
128
|
next if param.nil?
|
124
129
|
if param.type == :list
|
125
130
|
param.each do |p|
|
@@ -134,6 +139,7 @@ module Contracts
|
|
134
139
|
end
|
135
140
|
|
136
141
|
private
|
142
|
+
|
137
143
|
def build_param_element(param)
|
138
144
|
type = param.type
|
139
145
|
ident = param.jump(:ident, :label).last.to_sym
|
@@ -163,7 +169,8 @@ module Contracts
|
|
163
169
|
# which are key value pairs of the Hash and build from that.
|
164
170
|
result = {}
|
165
171
|
hash.each do |h|
|
166
|
-
result[h[0].jump(:label).last.to_sym] =
|
172
|
+
result[h[0].jump(:label).last.to_sym] =
|
173
|
+
Contracts::Formatters::InspectWrapper.new(type(h[1]))
|
167
174
|
end
|
168
175
|
result
|
169
176
|
end
|
@@ -171,7 +178,9 @@ module Contracts
|
|
171
178
|
# Formats Array type.
|
172
179
|
def array_type(array)
|
173
180
|
# This works because Ast inherits from Array.
|
174
|
-
array.map
|
181
|
+
array.map do |v|
|
182
|
+
Contracts::Formatters::InspectWrapper.new(type(v))
|
183
|
+
end.inspect
|
175
184
|
end
|
176
185
|
end
|
177
186
|
|
@@ -190,7 +199,7 @@ module Contracts
|
|
190
199
|
param_type, param = param
|
191
200
|
|
192
201
|
on_named = param_type == :named_arg ||
|
193
|
-
|
202
|
+
(named_count > 0 && param_type == :ident)
|
194
203
|
i -= named_count if on_named
|
195
204
|
|
196
205
|
type, type_ast = @types[i]
|
@@ -240,18 +249,15 @@ module Contracts
|
|
240
249
|
end
|
241
250
|
|
242
251
|
private
|
252
|
+
|
243
253
|
# The contract starts as a string, but we need to get it's real value
|
244
254
|
# so that we can call to_s on it.
|
245
255
|
def get_contract_value(type)
|
246
256
|
con = type
|
247
257
|
begin
|
248
258
|
con = Contracts.const_get(type)
|
249
|
-
rescue
|
250
|
-
|
251
|
-
con = eval(type)
|
252
|
-
rescue Exception
|
253
|
-
con
|
254
|
-
end
|
259
|
+
rescue StandardError # NameError
|
260
|
+
con = eval(type) rescue StandardError
|
255
261
|
end
|
256
262
|
con
|
257
263
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yard-contracts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon George
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yard
|