cloud_former 0.4.12 → 0.5.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.
- checksums.yaml +4 -4
- data/lib/cloud_former.rb +12 -0
- data/lib/cloud_former/has_properties_and_attributes.rb +10 -4
- data/lib/cloud_former/resource_properties/route53/alias_target.rb +10 -0
- data/lib/cloud_former/resource_properties/route53/geo_location.rb +10 -0
- data/lib/cloud_former/resource_properties/route53/hosted_zone_config.rb +8 -0
- data/lib/cloud_former/resource_properties/route53/hosted_zone_tag.rb +9 -0
- data/lib/cloud_former/resource_properties/route53/hosted_zone_vpc.rb +9 -0
- data/lib/cloud_former/resources/list.rb +25 -0
- data/lib/cloud_former/resources/route53/hosted_zone.rb +11 -0
- data/lib/cloud_former/resources/route53/record_set.rb +21 -0
- data/lib/cloud_former/resources/route53/record_set_group.rb +11 -0
- data/lib/cloud_former/version.rb +1 -1
- data/spec/resources/list_spec.rb +79 -0
- data/spec/resources/route53_spec.rb +128 -0
- metadata +16 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df57f4eb0602f3095f6a30d112a6e403f4f44191
|
4
|
+
data.tar.gz: 8814c1be794511cb9e3b112f08856c0d719fb655
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10e270789e6da892b451f45d7d66bf04c9c2c75cb437f7212a09890513f514ad83e0507c9f00b5bb6439f025dc9607f517c672e10b73f4cbdf23750f6739e9a8
|
7
|
+
data.tar.gz: 40cf87c4c345782589a13d2307b4b6131c788c74b500d2e07a711f1e2bc5b4a4509d9e9801120d79c0117044bb847db8f68c81b2c75e3200d62970d9e5f15442
|
data/lib/cloud_former.rb
CHANGED
@@ -22,6 +22,7 @@ module CloudFormer
|
|
22
22
|
autoload :MetadataResource, 'cloud_former/metadata_resources/metadata_resource'
|
23
23
|
autoload :Resource, 'cloud_former/resources/resource'
|
24
24
|
autoload :ResourceProperty, 'cloud_former/resource_properties/resource_property'
|
25
|
+
autoload :List, 'cloud_former/resources/list'
|
25
26
|
|
26
27
|
module AutoScaling
|
27
28
|
autoload :AutoScalingGroup, 'cloud_former/resources/auto_scaling/auto_scaling_group'
|
@@ -193,6 +194,17 @@ module CloudFormer
|
|
193
194
|
autoload :Parameter, 'cloud_former/resource_properties/redshift/parameter'
|
194
195
|
end
|
195
196
|
|
197
|
+
module Route53
|
198
|
+
autoload :AliasTarget, 'cloud_former/resource_properties/route53/alias_target'
|
199
|
+
autoload :GeoLocation, 'cloud_former/resource_properties/route53/geo_location'
|
200
|
+
autoload :HostedZone, 'cloud_former/resources/route53/hosted_zone'
|
201
|
+
autoload :HostedZoneConfig, 'cloud_former/resource_properties/route53/hosted_zone_config'
|
202
|
+
autoload :HostedZoneTag, 'cloud_former/resource_properties/route53/hosted_zone_tag'
|
203
|
+
autoload :HostedZoneVPC, 'cloud_former/resource_properties/route53/hosted_zone_vpc'
|
204
|
+
autoload :RecordSet, 'cloud_former/resources/route53/record_set'
|
205
|
+
autoload :RecordSetGroup, 'cloud_former/resources/route53/record_set_group'
|
206
|
+
end
|
207
|
+
|
196
208
|
module S3
|
197
209
|
autoload :Bucket, 'cloud_former/resources/s3/bucket'
|
198
210
|
autoload :CorsConfiguration, 'cloud_former/resource_properties/s3/cors_configuration'
|
@@ -66,10 +66,16 @@ module CloudFormer
|
|
66
66
|
if options[:type] < CloudFormer::ResourceProperty || options[:type] < CloudFormer::Resource
|
67
67
|
value = if options[:list]
|
68
68
|
count = args.shift
|
69
|
-
count
|
70
|
-
|
71
|
-
self.nested_resources
|
72
|
-
|
69
|
+
if count == :list
|
70
|
+
instances = List.new(options, *args, &block).entries
|
71
|
+
self.nested_resources.concat(instances) if options[:type] < CloudFormer::Resource
|
72
|
+
instances
|
73
|
+
else
|
74
|
+
count.times.map do |i|
|
75
|
+
instance = options[:type].new(*args) { instance_exec(i, &block) }
|
76
|
+
self.nested_resources << instance if options[:type] < CloudFormer::Resource
|
77
|
+
instance
|
78
|
+
end
|
73
79
|
end
|
74
80
|
else
|
75
81
|
instance = options[:type].new(*args, &block)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html
|
2
|
+
module CloudFormer
|
3
|
+
module Route53
|
4
|
+
class AliasTarget < ResourceProperty
|
5
|
+
aws_attribute :dns_name, name: 'DNSName', type: String
|
6
|
+
aws_attribute :evaluate_target_health, type: Boolean
|
7
|
+
aws_attribute :hosted_zone_id, type: String
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-geolocation.html
|
2
|
+
module CloudFormer
|
3
|
+
module Route53
|
4
|
+
class GeoLocation < ResourceProperty
|
5
|
+
aws_attribute :continent_code, type: String
|
6
|
+
aws_attribute :country_code, type: String
|
7
|
+
aws_attribute :subdivision_code, type: String
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-hostedzone-hostedzonetags.html
|
2
|
+
module CloudFormer
|
3
|
+
module Route53
|
4
|
+
class HostedZoneTag < ResourceProperty
|
5
|
+
aws_attribute :key, type: String
|
6
|
+
aws_attribute :value, type: String
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-hostedzone-hostedzonevpcs.html
|
2
|
+
module CloudFormer
|
3
|
+
module Route53
|
4
|
+
class HostedZoneVPC < ResourceProperty
|
5
|
+
aws_attribute :vpc_id, name: 'VPCId', type: String
|
6
|
+
aws_attribute :vpc_region, name: 'VPCRegion', type: String
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CloudFormer
|
2
|
+
class List
|
3
|
+
def initialize(resource_options, &block)
|
4
|
+
@resource_options = resource_options
|
5
|
+
@entries = []
|
6
|
+
if block.arity == 0
|
7
|
+
instance_eval(&block)
|
8
|
+
else
|
9
|
+
block.call(self)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def entry(*args, &block)
|
14
|
+
@entries << @resource_options[:type].new(*args) do
|
15
|
+
if block.arity == 0
|
16
|
+
instance_eval(&block)
|
17
|
+
else
|
18
|
+
block.call(self)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :entries
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-hostedzone.html
|
2
|
+
module CloudFormer
|
3
|
+
module Route53
|
4
|
+
class HostedZone < Resource
|
5
|
+
aws_property :hosted_zone_config, type: HostedZoneConfig, embed: true
|
6
|
+
aws_property :hosted_zone_tags, type: HostedZoneTag, list: true, embed: true
|
7
|
+
aws_property :_name, type: String
|
8
|
+
aws_property :vpcs, name: 'VPCs', type: HostedZoneVPC, list: true, embed: true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html
|
2
|
+
module CloudFormer
|
3
|
+
module Route53
|
4
|
+
class RecordSet < Resource
|
5
|
+
aws_property :alias_target, type: AliasTarget, embed: true
|
6
|
+
aws_property :comment, type: String
|
7
|
+
aws_property :failover, type: String
|
8
|
+
aws_property :geo_location, type: GeoLocation, embed: true
|
9
|
+
aws_property :health_check_id, type: String
|
10
|
+
aws_property :hosted_zone_id, type: String
|
11
|
+
aws_property :hosted_zone_name, type: String
|
12
|
+
aws_property :_name, type: String
|
13
|
+
aws_property :region, type: String
|
14
|
+
aws_property :resource_records, type: String, list: true
|
15
|
+
aws_property :set_identifier, type: String
|
16
|
+
aws_property :ttl, name: 'TTL', type: String
|
17
|
+
aws_property :type, type: String
|
18
|
+
aws_property :weight, type: Integer
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordsetgroup.html
|
2
|
+
module CloudFormer
|
3
|
+
module Route53
|
4
|
+
class RecordSetGroup < Resource
|
5
|
+
aws_property :hosted_zone_id, type: String
|
6
|
+
aws_property :hosted_zone_name, type: String
|
7
|
+
aws_property :record_sets, type: RecordSet, list: true
|
8
|
+
aws_property :comment, type: String
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/cloud_former/version.rb
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CloudFormer::List do
|
4
|
+
let(:template) { CloudFormer::Template.new }
|
5
|
+
|
6
|
+
it "can build a list of resource properties" do
|
7
|
+
instance = CloudFormer::EC2::Instance.new('instance') do
|
8
|
+
tags :list do
|
9
|
+
entry do
|
10
|
+
key 'A'
|
11
|
+
value '1'
|
12
|
+
end
|
13
|
+
|
14
|
+
entry do
|
15
|
+
key 'B'
|
16
|
+
value '2'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
template.add_resource(instance)
|
22
|
+
|
23
|
+
expect(template.dump_json).to eq(
|
24
|
+
'AWSTemplateFormatVersion' => '2010-09-09',
|
25
|
+
'Resources' => {
|
26
|
+
'instance' => {
|
27
|
+
'Type' => 'AWS::EC2::Instance',
|
28
|
+
'Properties' => {
|
29
|
+
'Tags' => [
|
30
|
+
{
|
31
|
+
'Key' => 'A',
|
32
|
+
'Value' => '1',
|
33
|
+
},
|
34
|
+
{
|
35
|
+
'Key' => 'B',
|
36
|
+
'Value' => '2',
|
37
|
+
},
|
38
|
+
],
|
39
|
+
},
|
40
|
+
},
|
41
|
+
},
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "can build a list of resources" do
|
46
|
+
instance = CloudFormer::EC2::Instance.new('instance') do
|
47
|
+
network_interfaces :list do
|
48
|
+
entry do
|
49
|
+
description 'one'
|
50
|
+
end
|
51
|
+
|
52
|
+
entry do
|
53
|
+
description 'two'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
template.add_resource(instance)
|
59
|
+
|
60
|
+
expect(template.dump_json).to eq(
|
61
|
+
'AWSTemplateFormatVersion' => '2010-09-09',
|
62
|
+
'Resources' => {
|
63
|
+
'instance' => {
|
64
|
+
'Type' => 'AWS::EC2::Instance',
|
65
|
+
'Properties' => {
|
66
|
+
'NetworkInterfaces' => [
|
67
|
+
{
|
68
|
+
'Description' => 'one',
|
69
|
+
},
|
70
|
+
{
|
71
|
+
'Description' => 'two',
|
72
|
+
},
|
73
|
+
],
|
74
|
+
},
|
75
|
+
},
|
76
|
+
},
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CloudFormer::Route53 do
|
4
|
+
let(:template) { CloudFormer::Template.new }
|
5
|
+
|
6
|
+
it "supports hosted zones" do
|
7
|
+
hosted_zone = CloudFormer::Route53::HostedZone.new('hosted_zone') do
|
8
|
+
hosted_zone_config do
|
9
|
+
comment 'COMMENT'
|
10
|
+
end
|
11
|
+
hosted_zone_tags(1) do
|
12
|
+
key 'KEY'
|
13
|
+
value 'VALUE'
|
14
|
+
end
|
15
|
+
_name 'NAME'
|
16
|
+
vpcs(1) do
|
17
|
+
vpc_id 'VPC ID'
|
18
|
+
vpc_region 'VPC REGION'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
template.add_resource(hosted_zone)
|
22
|
+
|
23
|
+
expect(template.dump_json).to eq(
|
24
|
+
'AWSTemplateFormatVersion' => '2010-09-09',
|
25
|
+
'Resources' => {
|
26
|
+
'hosted_zone' => {
|
27
|
+
'Type' => 'AWS::Route53::HostedZone',
|
28
|
+
'Properties' => {
|
29
|
+
'HostedZoneConfig' => {
|
30
|
+
'Comment' => 'COMMENT',
|
31
|
+
},
|
32
|
+
'HostedZoneTags' => [
|
33
|
+
{
|
34
|
+
'Key' => 'KEY',
|
35
|
+
'Value' => 'VALUE',
|
36
|
+
},
|
37
|
+
],
|
38
|
+
'Name' => 'NAME',
|
39
|
+
'VPCs' => [
|
40
|
+
{
|
41
|
+
'VPCId' => 'VPC ID',
|
42
|
+
'VPCRegion' => 'VPC REGION',
|
43
|
+
},
|
44
|
+
],
|
45
|
+
},
|
46
|
+
}
|
47
|
+
}
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "supports record set groups" do
|
52
|
+
record_set = CloudFormer::Route53::RecordSet.new('record_set') do
|
53
|
+
alias_target do
|
54
|
+
dns_name 'DNS NAME'
|
55
|
+
evaluate_target_health true
|
56
|
+
hosted_zone_id 'HOSTED ZONE ID'
|
57
|
+
end
|
58
|
+
comment 'COMMENT'
|
59
|
+
failover 'FAILOVER'
|
60
|
+
geo_location do
|
61
|
+
continent_code 'CONTINENT CODE'
|
62
|
+
country_code 'COUNTRY CODE'
|
63
|
+
subdivision_code 'SUBDIVISION CODE'
|
64
|
+
end
|
65
|
+
health_check_id 'HEALTH CHECK ID'
|
66
|
+
hosted_zone_id 'HOSTED ZONE ID'
|
67
|
+
hosted_zone_name 'HOSTED ZONE NAME'
|
68
|
+
_name 'NAME'
|
69
|
+
region 'REGION'
|
70
|
+
resource_records ['RESOURCE RECORD']
|
71
|
+
set_identifier 'SET IDENTIFIER'
|
72
|
+
ttl 'TTL'
|
73
|
+
type 'TYPE'
|
74
|
+
weight 2
|
75
|
+
end
|
76
|
+
template.add_resource(record_set)
|
77
|
+
|
78
|
+
record_set_group = CloudFormer::Route53::RecordSetGroup.new('record_set_group') do
|
79
|
+
hosted_zone_id 'HOSTED ZONE ID'
|
80
|
+
hosted_zone_name 'HOSTED ZONE NAME'
|
81
|
+
record_sets [record_set]
|
82
|
+
comment 'COMMENT'
|
83
|
+
end
|
84
|
+
template.add_resource(record_set_group)
|
85
|
+
|
86
|
+
expect(template.dump_json).to eq(
|
87
|
+
'AWSTemplateFormatVersion' => '2010-09-09',
|
88
|
+
'Resources' => {
|
89
|
+
'record_set' => {
|
90
|
+
'Type' => 'AWS::Route53::RecordSet',
|
91
|
+
'Properties' => {
|
92
|
+
'AliasTarget' => {
|
93
|
+
'DNSName' => 'DNS NAME',
|
94
|
+
'EvaluateTargetHealth' => true,
|
95
|
+
'HostedZoneId' => 'HOSTED ZONE ID',
|
96
|
+
},
|
97
|
+
'Comment' => 'COMMENT',
|
98
|
+
'Failover' => 'FAILOVER',
|
99
|
+
'GeoLocation' => {
|
100
|
+
'ContinentCode' => 'CONTINENT CODE',
|
101
|
+
'CountryCode' => 'COUNTRY CODE',
|
102
|
+
'SubdivisionCode' => 'SUBDIVISION CODE',
|
103
|
+
},
|
104
|
+
'HealthCheckId' => 'HEALTH CHECK ID',
|
105
|
+
'HostedZoneId' => 'HOSTED ZONE ID',
|
106
|
+
'HostedZoneName' => 'HOSTED ZONE NAME',
|
107
|
+
'Name' => 'NAME',
|
108
|
+
'Region' => 'REGION',
|
109
|
+
'ResourceRecords' => ['RESOURCE RECORD'],
|
110
|
+
'SetIdentifier' => 'SET IDENTIFIER',
|
111
|
+
'TTL' => 'TTL',
|
112
|
+
'Type' => 'TYPE',
|
113
|
+
'Weight' => 2,
|
114
|
+
},
|
115
|
+
},
|
116
|
+
'record_set_group' => {
|
117
|
+
'Type' => 'AWS::Route53::RecordSetGroup',
|
118
|
+
'Properties' => {
|
119
|
+
'HostedZoneId' => 'HOSTED ZONE ID',
|
120
|
+
'HostedZoneName' => 'HOSTED ZONE NAME',
|
121
|
+
'RecordSets' => [{'Ref' => 'record_set'}],
|
122
|
+
'Comment' => 'COMMENT',
|
123
|
+
},
|
124
|
+
},
|
125
|
+
},
|
126
|
+
)
|
127
|
+
end
|
128
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloud_former
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aubrey Holland
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -160,6 +160,11 @@ files:
|
|
160
160
|
- lib/cloud_former/resource_properties/rds/security_group_rule.rb
|
161
161
|
- lib/cloud_former/resource_properties/redshift/parameter.rb
|
162
162
|
- lib/cloud_former/resource_properties/resource_property.rb
|
163
|
+
- lib/cloud_former/resource_properties/route53/alias_target.rb
|
164
|
+
- lib/cloud_former/resource_properties/route53/geo_location.rb
|
165
|
+
- lib/cloud_former/resource_properties/route53/hosted_zone_config.rb
|
166
|
+
- lib/cloud_former/resource_properties/route53/hosted_zone_tag.rb
|
167
|
+
- lib/cloud_former/resource_properties/route53/hosted_zone_vpc.rb
|
163
168
|
- lib/cloud_former/resource_properties/s3/cors_configuration.rb
|
164
169
|
- lib/cloud_former/resource_properties/s3/cors_rule.rb
|
165
170
|
- lib/cloud_former/resource_properties/s3/lifecycle_configuration.rb
|
@@ -233,6 +238,7 @@ files:
|
|
233
238
|
- lib/cloud_former/resources/iam/user.rb
|
234
239
|
- lib/cloud_former/resources/iam/user_to_group_addition.rb
|
235
240
|
- lib/cloud_former/resources/kinesis/stream.rb
|
241
|
+
- lib/cloud_former/resources/list.rb
|
236
242
|
- lib/cloud_former/resources/rds/db_instance.rb
|
237
243
|
- lib/cloud_former/resources/rds/db_parameter_group.rb
|
238
244
|
- lib/cloud_former/resources/rds/db_security_group.rb
|
@@ -243,6 +249,9 @@ files:
|
|
243
249
|
- lib/cloud_former/resources/redshift/cluster_security_group_ingress.rb
|
244
250
|
- lib/cloud_former/resources/redshift/cluster_subnet_group.rb
|
245
251
|
- lib/cloud_former/resources/resource.rb
|
252
|
+
- lib/cloud_former/resources/route53/hosted_zone.rb
|
253
|
+
- lib/cloud_former/resources/route53/record_set.rb
|
254
|
+
- lib/cloud_former/resources/route53/record_set_group.rb
|
246
255
|
- lib/cloud_former/resources/s3/bucket.rb
|
247
256
|
- lib/cloud_former/resources/sns/topic.rb
|
248
257
|
- lib/cloud_former/resources/sqs/queue.rb
|
@@ -258,6 +267,8 @@ files:
|
|
258
267
|
- spec/resources/auto_scaling/notification_configuration_spec.rb
|
259
268
|
- spec/resources/iam/access_key_spec.rb
|
260
269
|
- spec/resources/iam/user_spec.rb
|
270
|
+
- spec/resources/list_spec.rb
|
271
|
+
- spec/resources/route53_spec.rb
|
261
272
|
- spec/spec_helper.rb
|
262
273
|
- spec/template_spec.rb
|
263
274
|
- spec/type_enforcement.rb
|
@@ -282,7 +293,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
282
293
|
version: '0'
|
283
294
|
requirements: []
|
284
295
|
rubyforge_project:
|
285
|
-
rubygems_version: 2.4.
|
296
|
+
rubygems_version: 2.4.8
|
286
297
|
signing_key:
|
287
298
|
specification_version: 4
|
288
299
|
summary: A Ruby DSL for creating CloudFormation templates
|
@@ -296,6 +307,8 @@ test_files:
|
|
296
307
|
- spec/resources/auto_scaling/notification_configuration_spec.rb
|
297
308
|
- spec/resources/iam/access_key_spec.rb
|
298
309
|
- spec/resources/iam/user_spec.rb
|
310
|
+
- spec/resources/list_spec.rb
|
311
|
+
- spec/resources/route53_spec.rb
|
299
312
|
- spec/spec_helper.rb
|
300
313
|
- spec/template_spec.rb
|
301
314
|
- spec/type_enforcement.rb
|