cfer 0.5.0.pre.rc4 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 920b540c1393d65eca22f5058ef46209581064a3
4
- data.tar.gz: 305ea70aebc10866edf04d318581002a0d6d23ed
3
+ metadata.gz: 78cb715113442fbbec2fa9c33e2e243bd048960c
4
+ data.tar.gz: f48b5126eebba1e069e2a26f8de51d9fc5f49d80
5
5
  SHA512:
6
- metadata.gz: a0641e4b71578c1eca5891ceeff60caa79a065462627efc8abd44ae9065b7ec71024c1f4f8f811efb709f06bccd95128a9aa2e3f289dcd8ed042a06d3f6fc46b
7
- data.tar.gz: 44f48d246f170fb5f6af197c606fdc40927de89c858ae83577ddb35260e5307975b2e59df80acbc146ba454693924708d6c3cb8ec253c9970acbe5bd5f70cd1d
6
+ metadata.gz: 16f2f7eec9dab63812568214952a1aee5668a9553c4c9156346f9a8dffe43e07a6a63e0667bb8491ce9d225493a631c5132af794afb5679bb43afd69896bfa9d
7
+ data.tar.gz: c4978b1220c8ce036a6fb4b2b96d695af2cd39b79a18e50371a58434102c8803df735ca18c0625a494c6d58bd798a6de0a82c855c6ce42bdd3fc89ae251319a5
@@ -12,6 +12,8 @@ engines:
12
12
  enabled: true
13
13
  rubocop:
14
14
  enabled: true
15
+ exclude_fingerprints:
16
+ - 9d7be17b9e5e786560cf0df662f55736
15
17
  ratings:
16
18
  paths:
17
19
  - "**.inc"
@@ -14,6 +14,7 @@ branches:
14
14
  - develop
15
15
  script:
16
16
  - bundle exec rspec
17
+ - bundle exec codeclimate-test-reporter
17
18
  - bundle exec yard
18
19
  addons:
19
20
  code_climate:
data/Gemfile CHANGED
@@ -7,8 +7,9 @@ group :test do
7
7
  gem 'rspec'
8
8
  gem 'rspec-mocks'
9
9
  gem 'guard-rspec'
10
- gem 'coveralls', require: false
11
- gem "codeclimate-test-reporter", require: nil
10
+ gem 'simplecov'
11
+ gem 'rubocop', '~> 0.47.1'
12
+ gem "codeclimate-test-reporter", "~> 1.0.0"
12
13
  end
13
14
 
14
15
  group :debug do
data/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  Cfer is a lightweight toolkit for managing CloudFormation templates.
11
11
 
12
- Read about Cfer [here](http://tilmonedwards.com/2015/07/28/cfer.html).
12
+ Read about Cfer [here](https://github.com/seanedwards/cfer/blob/master/examples/vpc.md).
13
13
 
14
14
  ## Support
15
15
 
@@ -247,5 +247,5 @@ This project also contains a [Code of Conduct](https://github.com/seanedwards/cf
247
247
 
248
248
  # Release Notes
249
249
 
250
- [Change Log](https://github.com/seanedwards/cfer/CHANGELOG.md)
250
+ [Change Log](https://github.com/seanedwards/cfer/blob/master/CHANGELOG.md)
251
251
 
data/bin/cfer CHANGED
@@ -6,7 +6,7 @@ module Cfer
6
6
  DEBUG = false
7
7
  end
8
8
 
9
- require 'cfer'
9
+ require 'cfer/cli'
10
10
 
11
11
 
12
12
  Cfer::Cli::main(ARGV)
@@ -0,0 +1,194 @@
1
+ When I first encountered AWS CloudFormation, I was appalled by the format for about ten minutes. This is the criticism of it that I've heard most often: the unwieldy syntax makes it unapproachable. Writing it by hand is worse than lunch meetings. I don't disagree.
2
+
3
+ However, I think CloudFormation makes a pretty decent intermediate language. Users of Elasic Beanstalk might notice a bunch of CloudFormation stacks in their account, all containing some kind of Amazon-produced EB magic. This is where CloudFormation excels: Machine-generated infrastructure.
4
+
5
+ To that end, I took a couple weekends and wrote [Cfer](https://github.com/seanedwards/cfer), a DSL for generating CloudFormation templates in Ruby. [I'm](http://chrisfjones.github.io/coffin/) [not](https://github.com/bazaarvoice/cloudformation-ruby-dsl) [the](https://github.com/stevenjack/cfndsl) [only](https://github.com/Optaros/cloud_builder) [one](https://github.com/rapid7/convection) [doing](https://github.com/cloudtools/troposphere) [this](https://cfn-pyplates.readthedocs.org/en/latest/). But I'll run through an example template, which will help you build a basic VPC in AWS, and at the same time, address some of the features of Cfer that might make CloudFormation a little more appealing to you.
6
+
7
+ If you find the format of this post difficult to follow, you can see this same example as a fully functional template in [examples/vpc.rb](https://github.com/seanedwards/cfer/blob/develop/examples/vpc.rb)
8
+
9
+
10
+ This template creates the following resources for a basic beginning AWS VPC setup:
11
+
12
+ 1. A VPC
13
+ 2. A route table to control network routing
14
+ 3. An Internet gateway to route traffic to the public internet
15
+ 4. 3 subnets, one in each of the account's first 3 availability zones
16
+ 5. A default network route to the IGW
17
+ 6. Associated plumbing resources to link it all together
18
+
19
+ ## Template Parameters
20
+
21
+ Template parameters allow you to use the same template to build multiple similar instances of parts of your infrastructure. Parameters may be defined using the `parameter` function:
22
+
23
+ ```ruby
24
+ parameter :VpcName, default: 'Example VPC'
25
+ ```
26
+
27
+ Resources are created using the `resource` function, accepting the following arguments:
28
+
29
+ 1. The resource name (string or symbol)
30
+ 2. The resource type. See the AWS CloudFormation docs for the [available resource types](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html).
31
+
32
+
33
+ ## The VPC Resource
34
+
35
+ The VPC is the foundation of your private network in AWS.
36
+
37
+ ```ruby
38
+ resource :vpc, 'AWS::EC2::VPC' do
39
+ ```
40
+
41
+ Each line within the resource block sets a single property. These properties are simply camelized using the ActiveSupport gem's `camelize` function. This means that the `cidr_block` function will set the `CidrBlock` property.
42
+
43
+ ```ruby
44
+ cidr_block '172.42.0.0/16'
45
+ ```
46
+
47
+ Following this pattern, `enable_dns_support` sets the `EnableDnsSupport` property.
48
+
49
+ ```ruby
50
+ enable_dns_support true
51
+ enable_dns_hostnames true
52
+ instance_tenancy 'default'
53
+ ```
54
+
55
+ The `tag` function is available on all resources, and adds keys to the resource's `Tags` property. It accepts the following arguments:
56
+
57
+ 1. Tag name (symbol or string)
58
+ 2. Tag value
59
+
60
+ ```ruby
61
+ tag :DefaultVpc, true
62
+ ```
63
+
64
+ Parameters are required at template generation time, and therefore may be referenced using the `parameters` hash anywhere in a template. This will render the parameter value as a string constant in the CloudFormation JSON output.
65
+
66
+ ```ruby
67
+ tag :Name, parameters[:VpcName]
68
+ ```
69
+
70
+ Finally, we can finish this resource by closing the block that we started when we called the `resource` function.
71
+
72
+ ```ruby
73
+ end
74
+ ```
75
+
76
+ ## The Internet Gateway
77
+
78
+ Instances in your VPC will need to be able to access the internet somehow, and an internet gateway is the mechanism for making this happen. Let's create one.
79
+
80
+ If there are no properties to set on a resource, the `do..end` block may be omitted entirely
81
+
82
+ ```ruby
83
+ resource :defaultigw, 'AWS::EC2::InternetGateway'
84
+ ```
85
+
86
+ ## Attaching the Gateway
87
+
88
+ For a gateway to be routable, it needs to be attached to a specific VPC using a "VPC Gateway Attachment" resource.
89
+
90
+ `Fn::ref` serves the same purpose as CloudFormation's `{"Ref": ""}` intrinsic function.
91
+
92
+ ```ruby
93
+ resource :vpcigw, 'AWS::EC2::VPCGatewayAttachment' do
94
+ vpc_id Fn::ref(:vpc)
95
+ internet_gateway_id Fn::ref(:defaultigw)
96
+ end
97
+ ```
98
+
99
+ ## The Route Table
100
+
101
+ A VPC also needs a route table. Every VPC comes with a default route table, but I like to create my own resources so that they're all expressed in the template.
102
+
103
+ ```ruby
104
+ resource :routetable, 'AWS::EC2::RouteTable' do
105
+ vpc_id Fn::ref(:vpc)
106
+ end
107
+ ```
108
+
109
+ ## The Default Route
110
+
111
+ We also have to set up a default route, so that any traffic that the VPC doesn't recognize gets routed off to the internet gateway.
112
+
113
+ The `resource` function accepts one additional parameter that was not addressed above: the options hash. Additional options passed here will be placed inside the resource, but outside the `Properties` block. In this case, we've specified that the default route explicitly depends on the VPC Internet Gateway.
114
+
115
+ As of this writing, this is actually a required workaround for this template. The gateway must be attached to the VPC before a route can be created to it, but since the gateway attachment isn't actually referenced anywhere in this resource, we need to explicitly declare that dependency.
116
+
117
+ ```ruby
118
+ resource :defaultroute, 'AWS::EC2::Route', DependsOn: [:vpcigw] do
119
+ route_table_id Fn::ref(:routetable)
120
+ gateway_id Fn::ref(:defaultigw)
121
+ destination_cidr_block '0.0.0.0/0'
122
+ end
123
+ ```
124
+
125
+ ## The Subnets
126
+
127
+ Naturally, you'll also need networks. Like the route table, I like to create my own so that I have control of their configuration inside the template.
128
+
129
+ Notice `Fn::select`, `Fn::get_azs` and `AWS::region` in this snippet. These all map to the CloudFormation functions and variables of the same name.
130
+
131
+ We'll use Ruby to create three identical subnets:
132
+
133
+ ```ruby
134
+ (1..3).each do |i|
135
+ ```
136
+
137
+ The subnets themselves will be in the first three availability zones of the account. A more sophisticated template might want to handle this differently.
138
+
139
+ ```ruby
140
+ resource "subnet#{i}", 'AWS::EC2::Subnet' do
141
+ availability_zone Fn::select(i, Fn::get_azs(AWS::region))
142
+ cidr_block "172.42.#{i}.0/24"
143
+ vpc_id Fn::ref(:vpc)
144
+ end
145
+ ```
146
+
147
+ Now the subnet needs to be associated with the route table, so that hosts in the subnet are able to access the rest of the network and the internet.
148
+
149
+ ```ruby
150
+ resource "srta#{i}".to_sym, 'AWS::EC2::SubnetRouteTableAssociation' do
151
+ subnet_id Fn::ref("subnet#{i}")
152
+ route_table_id Fn::ref(:routetable)
153
+ end
154
+ ```
155
+
156
+ We can use the `output` function to output the subnet IDs we've just created. We'll go over how Cfer makes this useful in part 2 of this post.
157
+
158
+ ```ruby
159
+ output "subnetid#{i}", Fn::ref("subnet#{i}")
160
+ ```
161
+
162
+ And of course, end the iteration block.
163
+
164
+ ```ruby
165
+ end
166
+ ```
167
+
168
+
169
+ Finally, let's output the VPC ID too, since we'll probably need that in other templates.
170
+
171
+ ```ruby
172
+ output :vpcid, Fn::ref(:vpc)
173
+ ```
174
+
175
+ ## Converging the Stack
176
+
177
+ Now that you have your template ready, you'll be able to use Cfer to create or update a CloudFormation stack:
178
+
179
+ {% highlight bash %}
180
+ cfer converge vpc -t examples/vpc.rb --profile ${AWS_PROFILE} --region ${AWS_REGION}
181
+ ```
182
+
183
+ Which should produce something like this.
184
+
185
+ ![Cfer Demo]({{ site.url }}/images/cfer/cfer-demo.gif)
186
+
187
+ Use `cfer help` to get more usage information, or check `README.md` and `Rakefile` in the source repository to see how to embed Cfer into your own projects.
188
+
189
+ ## In Part 2...
190
+
191
+ In part 2, we'll go over some additional features of Cfer. If you want a preview, you can check out the [instance.rb](https://github.com/seanedwards/cfer/blob/develop/examples/instance.rb) example, which covers how you can use Cfer to create security groups, instances with automated provisioning, and how to automatically look up outputs from other stacks.
192
+
193
+ Cfer can be found on [GitHub](https://github.com/seanedwards/cfer) and [RubyGems](https://rubygems.org/gems/cfer) and is MIT licensed. Pull requests are welcome.
194
+
@@ -64,7 +64,7 @@ module Cfer
64
64
  cfn = options[:aws_options] || {}
65
65
 
66
66
  cfn_stack = options[:cfer_client] || Cfer::Cfn::Client.new(cfn.merge(stack_name: stack_name))
67
- raise Cfer::Util::CferError, "No such template file: #{tmpl}" unless File.exists?(tmpl) || options[:cfer_stack]
67
+ raise Cfer::Util::CferError, "No such template file: #{tmpl}" unless File.exist?(tmpl) || options[:cfer_stack]
68
68
  stack =
69
69
  options[:cfer_stack] ||
70
70
  Cfer::stack_from_file(tmpl,
@@ -126,7 +126,7 @@ module Cfer
126
126
  when 'table', nil
127
127
  puts "Status: #{cfn_stack[:stack_status]}"
128
128
  puts "Description: #{cfn_stack[:description]}" if cfn_stack[:description]
129
- puts "Created with Cfer version: #{Semantic::Version.new(cfer_version_str).to_s} (current: #{Cfer::SEMANTIC_VERSION.to_s})" if cfer_version
129
+ puts "Created with Cfer version: #{Semantic::Version.new(cfer_version_str)} (current: #{Cfer::SEMANTIC_VERSION.to_s})" if cfer_version
130
130
  puts ""
131
131
  def tablify(list, type)
132
132
  list ||= []
@@ -165,7 +165,7 @@ module Cfer
165
165
  cfn = options[:aws_options] || {}
166
166
 
167
167
  cfn_stack = options[:cfer_client] || Cfer::Cfn::Client.new(cfn)
168
- raise Cfer::Util::CferError, "No such template file: #{tmpl}" unless File.exists?(tmpl) || options[:cfer_stack]
168
+ raise Cfer::Util::CferError, "No such template file: #{tmpl}" unless File.exist?(tmpl) || options[:cfer_stack]
169
169
  stack = options[:cfer_stack] || Cfer::stack_from_file(tmpl,
170
170
  options.merge(client: cfn_stack, parameters: generate_final_parameters(options))).to_h
171
171
  puts render_json(stack, options)
@@ -333,7 +333,6 @@ end
333
333
  %w{
334
334
  version.rb
335
335
  block.rb
336
- cli.rb
337
336
  config.rb
338
337
 
339
338
  util/error.rb
@@ -36,7 +36,7 @@ module Cfer
36
36
 
37
37
  def include_file(file)
38
38
  Preconditions.check(file).is_not_nil
39
- raise Cfer::Util::FileDoesNotExistError, "#{file} does not exist." unless File.exists?(file)
39
+ raise Cfer::Util::FileDoesNotExistError, "#{file} does not exist." unless File.exist?(file)
40
40
 
41
41
  case File.extname(file)
42
42
  when '.json'
@@ -121,7 +121,6 @@ module Cfer::Cfn
121
121
  stack_options[:timeout_in_minutes] = options[:timeout] if options[:timeout]
122
122
 
123
123
  stack_options.merge! parse_stack_policy(:stack_policy, options[:stack_policy])
124
- stack_options.merge! parse_stack_policy(:stack_policy_during_update, options[:stack_policy_during_update])
125
124
 
126
125
  stack_options.merge! template_options
127
126
 
@@ -133,6 +132,7 @@ module Cfer::Cfn
133
132
  if options[:change]
134
133
  create_change_set stack_options.merge change_set_name: options[:change], description: options[:change_description], parameters: update_params
135
134
  else
135
+ stack_options.merge! parse_stack_policy(:stack_policy_during_update, options[:stack_policy_during_update])
136
136
  update_stack stack_options.merge parameters: update_params
137
137
  end
138
138
  :updated
@@ -1,3 +1,4 @@
1
+ require 'cfer'
1
2
  require 'cri'
2
3
  require 'rainbow'
3
4
  require 'table_print'
@@ -5,7 +5,7 @@ module Cfer
5
5
  DEBUG = true
6
6
  end
7
7
 
8
- require "cfer"
8
+ require "cfer/cli"
9
9
 
10
10
  Cfer::LOGGER.level = Logger::DEBUG
11
11
 
@@ -20,14 +20,6 @@ module Cfer::Core::Functions
20
20
  {"Fn::Select" => [i, o]}
21
21
  end
22
22
 
23
- def base64(v)
24
- {"Fn::Base64" => v}
25
- end
26
-
27
- def condition(cond)
28
- {"Condition" => cond}
29
- end
30
-
31
23
  def and(*conds)
32
24
  {"Fn::And" => conds}
33
25
  end
@@ -52,35 +44,31 @@ module Cfer::Core::Functions
52
44
  {"Fn::GetAZs" => region}
53
45
  end
54
46
 
55
- def account_id
56
- Fn::ref 'AWS::AccountId'
47
+ def sub(str, vals = {})
48
+ {"Fn::Sub" => [str, vals]}
57
49
  end
58
50
 
59
51
  def notification_arns
60
- Fn::ref 'AWS::NotificationARNs'
61
- end
62
-
63
- def no_value
64
- Fn::ref 'AWS::NoValue'
65
- end
66
-
67
- def region
68
- Fn::ref 'AWS::Region'
69
- end
70
-
71
- def stack_id
72
- Fn::ref 'AWS::StackId'
73
- end
74
-
75
- def stack_name
76
- Fn::ref 'AWS::StackName'
52
+ ref 'AWS::NotificationARNs'
77
53
  end
78
54
  end
79
55
 
80
56
  module Cfer::Core::Functions::AWS
81
57
  extend Cfer::Core::Functions
58
+
59
+ def self.method_missing(sym, *args)
60
+ method = sym.to_s.camelize
61
+ raise "AWS::#{method} does not accept arguments" unless args.empty?
62
+ ref "AWS::#{method}"
63
+ end
82
64
  end
83
65
 
84
66
  module Cfer::Core::Functions::Fn
85
67
  extend Cfer::Core::Functions
68
+
69
+ def self.method_missing(sym, *args)
70
+ method = sym.to_s.camelize
71
+ raise "Fn::#{method} requires one argument" unless args.size == 1
72
+ { "Fn::#{method}" => args.first }
73
+ end
86
74
  end
@@ -2,14 +2,14 @@ module Cfer::Core
2
2
  # Provides support for hooking into resource types, and evaluating code before or after properties are set
3
3
  module Hooks
4
4
  def pre_block
5
- self.class.pre_hooks.each do |hook|
6
- instance_eval &hook
5
+ self.class.pre_hooks.sort { |a, b| (a[:nice] || 0) <=> (b[:nice] || 0) }.each do |hook|
6
+ Docile.dsl_eval(self, &hook[:block])
7
7
  end
8
8
  end
9
9
 
10
10
  def post_block
11
- self.class.post_hooks.each do |hook|
12
- instance_eval &hook
11
+ self.class.post_hooks.sort { |a, b| (a[:nice] || 0) <=> (b[:nice] || 0) }.each do |hook|
12
+ Docile.dsl_eval(self, &hook[:block])
13
13
  end
14
14
  end
15
15
 
@@ -18,12 +18,12 @@ module Cfer::Core
18
18
  end
19
19
 
20
20
  module ClassMethods
21
- def before(&block)
22
- self.pre_hooks << block
21
+ def before(options = {}, &block)
22
+ self.pre_hooks << options.merge(block: block)
23
23
  end
24
24
 
25
- def after(&block)
26
- self.post_hooks << block
25
+ def after(options = {}, &block)
26
+ self.post_hooks << options.merge(block: block)
27
27
  end
28
28
 
29
29
  def pre_hooks
@@ -22,6 +22,7 @@ module Cfer::Core
22
22
  # @param options [Hash] An arbitrary set of additional properties to be added to this tag, for example `PropagateOnLaunch` on `AWS::AutoScaling::AutoScalingGroup`
23
23
  def tag(k, v, **options)
24
24
  self[:Properties][:Tags] ||= []
25
+ self[:Properties][:Tags].delete_if { |kv| kv["Key"] == k }
25
26
  self[:Properties][:Tags].unshift({"Key" => k, "Value" => v}.merge(options))
26
27
  end
27
28
 
@@ -53,14 +54,14 @@ module Cfer::Core
53
54
 
54
55
  # Registers a hook that will be run before properties are set on a resource
55
56
  # @param type [String] The type of resource, for example `AWS::EC2::Instance`
56
- def before(type, &block)
57
- resource_class(type).pre_hooks << block
57
+ def before(type, options = {}, &block)
58
+ resource_class(type).pre_hooks << options.merge(block: block)
58
59
  end
59
60
 
60
61
  # Registers a hook that will be run after properties have been set on a resource
61
62
  # @param type [String] The type of resource, for example `AWS::EC2::Instance`
62
- def after(type, &block)
63
- resource_class(type).post_hooks << block
63
+ def after(type, options = {}, &block)
64
+ resource_class(type).post_hooks << options.merge(block: block)
64
65
  end
65
66
  end
66
67
  end
@@ -1,5 +1,5 @@
1
1
  module Cfer
2
- VERSION = "0.5.0-rc4"
2
+ VERSION = "0.5.0"
3
3
 
4
4
  begin
5
5
  require 'semantic'
@@ -26,6 +26,10 @@ module CferExt
26
26
  end
27
27
 
28
28
  module WithPolicyDocument
29
+ def policy_document(doc = nil, &block)
30
+ doc = CferExt::AWS::IAM.generate_policy(&block) if doc == nil
31
+ self[:Properties][:PolicyDocument] = doc
32
+ end
29
33
  end
30
34
 
31
35
  module WithPolicies
@@ -0,0 +1,11 @@
1
+ require 'docile'
2
+
3
+ Cfer::Core::Resource.extend_resource "AWS::Route53::RecordSetGroup" do
4
+ %w{a aaaa cname mx ns ptr soa spf srv txt}.each do |type|
5
+ define_method type.to_sym do |name, records, options = {}|
6
+ self[:Properties][:RecordSets] ||= []
7
+ self[:Properties][:RecordSets] << options.merge(Type: type.upcase, Name: name, ResourceRecords: [ records ].flatten)
8
+ end
9
+ end
10
+ end
11
+
@@ -38,7 +38,7 @@ Cfer::Core::Stack.extend_stack do
38
38
  end
39
39
  end
40
40
 
41
- Cfer::Core::Stack.after do
41
+ Cfer::Core::Stack.after(nice: 100) do
42
42
  begin
43
43
  validate_stack!(self)
44
44
  rescue Cfer::Util::CferValidationError => e
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0.pre.rc4
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Edwards
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-05 00:00:00.000000000 Z
11
+ date: 2017-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docile
@@ -223,6 +223,7 @@ files:
223
223
  - doc/cfer-demo.gif
224
224
  - examples/common/instance_deps.rb
225
225
  - examples/instance.rb
226
+ - examples/vpc.md
226
227
  - examples/vpc.rb
227
228
  - lib/cfer.rb
228
229
  - lib/cfer/block.rb
@@ -244,6 +245,7 @@ files:
244
245
  - lib/cferext/aws/iam/policy_generator.rb
245
246
  - lib/cferext/aws/kms/key.rb
246
247
  - lib/cferext/aws/rds/db_instance.rb
248
+ - lib/cferext/aws/route53/record_dsl.rb
247
249
  - lib/cferext/cfer/stack_validation.rb
248
250
  homepage: https://github.com/seanedwards/cfer
249
251
  licenses:
@@ -263,9 +265,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
263
265
  version: 2.2.5
264
266
  required_rubygems_version: !ruby/object:Gem::Requirement
265
267
  requirements:
266
- - - ">"
268
+ - - ">="
267
269
  - !ruby/object:Gem::Version
268
- version: 1.3.1
270
+ version: '0'
269
271
  requirements: []
270
272
  rubyforge_project:
271
273
  rubygems_version: 2.5.1