geoengineer 0.1.0 → 0.1.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
- checksums.yaml.gz.sig +5 -0
- data.tar.gz.sig +0 -0
- data/README.md +5 -5
- data/lib/geoengineer/cli/geo_cli.rb +4 -5
- data/lib/geoengineer/cli/status_command.rb +7 -1
- data/lib/geoengineer/environment.rb +53 -51
- data/lib/geoengineer/project.rb +5 -24
- data/lib/geoengineer/resource.rb +89 -20
- data/lib/geoengineer/resources/aws_customer_gateway.rb +23 -0
- data/lib/geoengineer/resources/aws_eip.rb +43 -0
- data/lib/geoengineer/resources/aws_iam_group.rb +26 -0
- data/lib/geoengineer/resources/aws_iam_group_membership.rb +50 -0
- data/lib/geoengineer/resources/aws_iam_policy.rb +12 -4
- data/lib/geoengineer/resources/aws_iam_policy_attachment.rb +95 -0
- data/lib/geoengineer/resources/aws_iam_role.rb +45 -0
- data/lib/geoengineer/resources/aws_instance.rb +7 -4
- data/lib/geoengineer/resources/aws_internet_gateway.rb +23 -0
- data/lib/geoengineer/resources/aws_lambda_alias.rb +50 -0
- data/lib/geoengineer/resources/aws_lambda_event_source_mapping.rb +47 -0
- data/lib/geoengineer/resources/aws_lambda_function.rb +30 -0
- data/lib/geoengineer/resources/aws_lambda_permission.rb +74 -0
- data/lib/geoengineer/resources/aws_main_route_table_association.rb +51 -0
- data/lib/geoengineer/resources/aws_nat_gateway.rb +29 -0
- data/lib/geoengineer/resources/aws_network_acl.rb +38 -0
- data/lib/geoengineer/resources/aws_network_acl_rule.rb +50 -0
- data/lib/geoengineer/resources/aws_route.rb +47 -0
- data/lib/geoengineer/resources/aws_route53_record.rb +4 -0
- data/lib/geoengineer/resources/aws_route_table.rb +26 -0
- data/lib/geoengineer/resources/aws_route_table_association.rb +45 -0
- data/lib/geoengineer/resources/aws_security_group.rb +8 -5
- data/lib/geoengineer/resources/aws_subnet.rb +24 -0
- data/lib/geoengineer/resources/aws_vpc.rb +24 -0
- data/lib/geoengineer/resources/aws_vpc_dhcp_options.rb +29 -0
- data/lib/geoengineer/resources/aws_vpc_dhcp_options_association.rb +40 -0
- data/lib/geoengineer/resources/aws_vpc_endpoint.rb +26 -0
- data/lib/geoengineer/resources/aws_vpc_peering_connection.rb +29 -0
- data/lib/geoengineer/resources/aws_vpn_connection.rb +23 -0
- data/lib/geoengineer/resources/aws_vpn_connection_route.rb +35 -0
- data/lib/geoengineer/resources/aws_vpn_gateway.rb +22 -0
- data/lib/geoengineer/resources/aws_vpn_gateway_attachment.rb +41 -0
- data/lib/geoengineer/template.rb +20 -4
- data/lib/geoengineer/utils/aws_clients.rb +4 -0
- data/lib/geoengineer/utils/crc32.rb +61 -0
- data/lib/geoengineer/utils/has_attributes.rb +25 -11
- data/lib/geoengineer/utils/has_projects.rb +21 -0
- data/lib/geoengineer/utils/has_resources.rb +17 -4
- data/lib/geoengineer/utils/has_templates.rb +31 -0
- data/lib/geoengineer/utils/has_validations.rb +18 -3
- data/lib/geoengineer/version.rb +1 -1
- data/spec/environment_spec.rb +40 -19
- data/spec/project_spec.rb +2 -2
- data/spec/resource_spec.rb +87 -6
- data/spec/resources/aws_customer_gateway_spec.rb +24 -0
- data/spec/resources/aws_eip_spec.rb +29 -0
- data/spec/resources/aws_iam_group_membership_spec.rb +83 -0
- data/spec/resources/aws_iam_group_spec.rb +43 -0
- data/spec/resources/aws_iam_policy_attachment_spec.rb +80 -0
- data/spec/resources/{aws_iam_policy.rb → aws_iam_policy_spec.rb} +6 -5
- data/spec/resources/aws_iam_role_spec.rb +45 -0
- data/spec/resources/aws_internet_gateway_spec.rb +24 -0
- data/spec/resources/aws_lambda_alias_spec.rb +39 -0
- data/spec/resources/aws_lambda_event_source_mapping_spec.rb +53 -0
- data/spec/resources/aws_lambda_function_spec.rb +29 -0
- data/spec/resources/aws_lambda_permission_spec.rb +90 -0
- data/spec/resources/aws_main_route_table_association_spec.rb +57 -0
- data/spec/resources/aws_nat_gateway_spec.rb +31 -0
- data/spec/resources/aws_network_acl_rule_spec.rb +73 -0
- data/spec/resources/aws_network_acl_spec.rb +31 -0
- data/spec/resources/aws_route53_record_spec.rb +5 -0
- data/spec/resources/aws_route_spec.rb +47 -0
- data/spec/resources/aws_route_table_association_spec.rb +47 -0
- data/spec/resources/aws_route_table_spec.rb +24 -0
- data/spec/resources/aws_security_group_spec.rb +36 -2
- data/spec/resources/aws_subnet_spec.rb +24 -0
- data/spec/resources/aws_vpc_dhcp_options_association_spec.rb +43 -0
- data/spec/resources/aws_vpc_dhcp_options_spec.rb +24 -0
- data/spec/resources/aws_vpc_endpoint_spec.rb +41 -0
- data/spec/resources/aws_vpc_peering_connection_spec.rb +33 -0
- data/spec/resources/aws_vpc_spec.rb +24 -0
- data/spec/resources/aws_vpn_connection_route_spec.rb +43 -0
- data/spec/resources/aws_vpn_connection_spec.rb +41 -0
- data/spec/resources/aws_vpn_gateway_attachment_spec.rb +41 -0
- data/spec/resources/aws_vpn_gateway_spec.rb +39 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/utils/crc32_spec.rb +14 -0
- data/spec/utils/has_attributes_spec.rb +22 -0
- data/spec/utils/has_resources_spec.rb +4 -0
- data/spec/utils/has_validations_spec.rb +45 -0
- metadata +117 -6
- metadata.gz.sig +1 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
########################################################################
|
2
|
+
# AwsVpc is the +aws_vpc+ terrform resource,
|
3
|
+
#
|
4
|
+
# {https://www.terraform.io/docs/providers/aws/r/vpc.html Terraform Docs}
|
5
|
+
########################################################################
|
6
|
+
class GeoEngineer::Resources::AwsVpc < GeoEngineer::Resource
|
7
|
+
validate -> { validate_required_attributes([:cidr_block]) }
|
8
|
+
validate -> { validate_has_tag(:Name) }
|
9
|
+
validate -> { validate_cidr_block(self.cidr_block) if self.cidr_block }
|
10
|
+
|
11
|
+
after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
|
12
|
+
after :initialize, -> { _geo_id -> { NullObject.maybe(tags)[:Name] } }
|
13
|
+
|
14
|
+
def self._fetch_remote_resources
|
15
|
+
AwsClients.ec2.describe_vpcs['vpcs'].map(&:to_h).map do |vpc|
|
16
|
+
vpc.merge(
|
17
|
+
{
|
18
|
+
_terraform_id: vpc[:vpc_id],
|
19
|
+
_geo_id: vpc[:tags]&.find { |tag| tag[:key] == "Name" }&.dig(:value)
|
20
|
+
}
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
########################################################################
|
2
|
+
# AwsVpcDhcpOptions is the +aws_vpc_dhcp_options+ terrform resource,
|
3
|
+
#
|
4
|
+
# {https://www.terraform.io/docs/providers/aws/r/vpc_dhcp_options.html Terraform Docs}
|
5
|
+
########################################################################
|
6
|
+
class GeoEngineer::Resources::AwsVpcDhcpOptions < GeoEngineer::Resource
|
7
|
+
validate -> { validate_has_tag(:Name) }
|
8
|
+
validate -> {
|
9
|
+
validate_at_least_one_present(
|
10
|
+
%i(
|
11
|
+
domain_name domain_name_servers ntp_servers netbios_name_servers netbios_node_type
|
12
|
+
)
|
13
|
+
)
|
14
|
+
}
|
15
|
+
|
16
|
+
after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
|
17
|
+
after :initialize, -> { _geo_id -> { NullObject.maybe(tags)[:Name] } }
|
18
|
+
|
19
|
+
def self._fetch_remote_resources
|
20
|
+
AwsClients.ec2.describe_dhcp_options['dhcp_options'].map(&:to_h).map do |options|
|
21
|
+
options.merge(
|
22
|
+
{
|
23
|
+
_terraform_id: options[:dhcp_options_id],
|
24
|
+
_geo_id: options[:tags]&.find { |tag| tag[:key] == "Name" }&.dig(:value)
|
25
|
+
}
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
########################################################################
|
2
|
+
# AwsVpcDhcpOptionsAssociation is the +aws_vpc_dhcp_options_association+ terrform resource,
|
3
|
+
#
|
4
|
+
# {https://www.terraform.io/docs/providers/aws/r/vpc_dhcp_options_association.html Terraform Docs}
|
5
|
+
########################################################################
|
6
|
+
class GeoEngineer::Resources::AwsVpcDhcpOptionsAssociation < GeoEngineer::Resource
|
7
|
+
validate -> { validate_required_attributes([:dhcp_options_id, :vpc_id]) }
|
8
|
+
|
9
|
+
after :initialize, -> {
|
10
|
+
_terraform_id -> { "#{dhcp_options_id}-#{vpc_id}" }
|
11
|
+
}
|
12
|
+
|
13
|
+
def to_terraform_state
|
14
|
+
tfstate = super
|
15
|
+
tfstate[:primary][:attributes] = {
|
16
|
+
'vpc_id' => vpc_id,
|
17
|
+
'dhcp_options_id' => dhcp_options_id
|
18
|
+
}
|
19
|
+
tfstate
|
20
|
+
end
|
21
|
+
|
22
|
+
def support_tags?
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def self._fetch_remote_resources
|
27
|
+
AwsClients
|
28
|
+
.ec2
|
29
|
+
.describe_vpcs['vpcs']
|
30
|
+
.map(&:to_h)
|
31
|
+
.select { |vpc| vpc[:dhcp_options_id] }
|
32
|
+
.map do |vpc|
|
33
|
+
{
|
34
|
+
vpc_id: vpc[:vpc_id],
|
35
|
+
dhcp_options_id: vpc[:dhcp_options_id],
|
36
|
+
_terraform_id: "#{vpc[:dhcp_options_id]}-#{vpc[:vpc_id]}"
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
########################################################################
|
2
|
+
# AwsVpcEndpoint is the +aws_vpc_endpoint+ terrform resource,
|
3
|
+
#
|
4
|
+
# {https://www.terraform.io/docs/providers/aws/r/vpc_endpoint.html Terraform Docs}
|
5
|
+
########################################################################
|
6
|
+
class GeoEngineer::Resources::AwsVpcEndpoint < GeoEngineer::Resource
|
7
|
+
validate -> { validate_required_attributes([:vpc_id, :service_name]) }
|
8
|
+
|
9
|
+
after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
|
10
|
+
after :initialize, -> { _geo_id -> { "#{vpc_id}::#{service_name}" } }
|
11
|
+
|
12
|
+
def support_tags?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def self._fetch_remote_resources
|
17
|
+
AwsClients.ec2.describe_vpc_endpoints['vpc_endpoints'].map(&:to_h).map do |endpoint|
|
18
|
+
endpoint.merge(
|
19
|
+
{
|
20
|
+
_terraform_id: endpoint[:vpc_endpoint_id],
|
21
|
+
_geo_id: "#{endpoint[:vpc_id]}::#{endpoint[:service_name]}"
|
22
|
+
}
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
########################################################################
|
2
|
+
# AwsVpcPeeringConnection is the +aws_vpc_peering_connection+ terrform resource,
|
3
|
+
#
|
4
|
+
# {https://www.terraform.io/docs/providers/aws/r/vpc_peering.html Terraform Docs}
|
5
|
+
########################################################################
|
6
|
+
class GeoEngineer::Resources::AwsVpcPeeringConnection < GeoEngineer::Resource
|
7
|
+
validate -> { validate_required_attributes([:peer_owner_id, :peer_vpc_id, :vpc_id]) }
|
8
|
+
validate -> { validate_has_tag(:Name) }
|
9
|
+
|
10
|
+
after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
|
11
|
+
after :initialize, -> { _geo_id -> { NullObject.maybe(tags)[:Name] } }
|
12
|
+
|
13
|
+
def self._fetch_remote_resources
|
14
|
+
AwsClients
|
15
|
+
.ec2
|
16
|
+
.describe_vpc_peering_connections['vpc_peering_connections']
|
17
|
+
.map(&:to_h)
|
18
|
+
.map { |connection| _merge_ids(connection) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def self._merge_ids(connection)
|
22
|
+
connection.merge(
|
23
|
+
{
|
24
|
+
_terraform_id: connection[:vpc_peering_connection_id],
|
25
|
+
_geo_id: connection[:tags]&.find { |tag| tag[:key] == "Name" }&.dig(:value)
|
26
|
+
}
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
########################################################################
|
2
|
+
# AwsVpnConnection is the +aws_vpn_connection+ terrform resource,
|
3
|
+
#
|
4
|
+
# {https://www.terraform.io/docs/providers/aws/r/vpn_connection.html Terraform Docs}
|
5
|
+
########################################################################
|
6
|
+
class GeoEngineer::Resources::AwsVpnConnection < GeoEngineer::Resource
|
7
|
+
validate -> { validate_required_attributes([:customer_gateway_id, :vpn_gateway_id, :type]) }
|
8
|
+
validate -> { validate_has_tag(:Name) }
|
9
|
+
|
10
|
+
after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
|
11
|
+
after :initialize, -> { _geo_id -> { NullObject.maybe(tags)[:Name] } }
|
12
|
+
|
13
|
+
def self._fetch_remote_resources
|
14
|
+
AwsClients.ec2.describe_vpn_connections['vpn_connections'].map(&:to_h).map do |connection|
|
15
|
+
connection.merge(
|
16
|
+
{
|
17
|
+
_terraform_id: connection[:vpn_connection_id],
|
18
|
+
_geo_id: connection[:tags].find { |tag| tag[:key] == "Name" }&.dig(:value)
|
19
|
+
}
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
########################################################################
|
2
|
+
# AwsVpnConnectionRoute is the +aws_vpn_connection+ terrform resource,
|
3
|
+
#
|
4
|
+
# {https://www.terraform.io/docs/providers/aws/r/vpn_connection_route.html Terraform Docs}
|
5
|
+
########################################################################
|
6
|
+
class GeoEngineer::Resources::AwsVpnConnectionRoute < GeoEngineer::Resource
|
7
|
+
validate -> { validate_required_attributes([:destination_cidr_block, :vpn_connection_id]) }
|
8
|
+
|
9
|
+
after :initialize, -> { _terraform_id -> { "#{destination_cidr_block}:#{vpn_connection_id}" } }
|
10
|
+
|
11
|
+
def support_tags?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def self._fetch_remote_resources
|
16
|
+
AwsClients
|
17
|
+
.ec2
|
18
|
+
.describe_vpn_connections['vpn_connections']
|
19
|
+
.map(&:to_h)
|
20
|
+
.select { |connection| !connection[:routes].empty? }
|
21
|
+
.map { |connection| _generate_routes(connection) }
|
22
|
+
.flatten
|
23
|
+
end
|
24
|
+
|
25
|
+
def self._generate_routes(connection)
|
26
|
+
connection[:routes].map do |route|
|
27
|
+
route.merge(
|
28
|
+
{
|
29
|
+
_terraform_id: "#{route[:destination_cidr_block]}:#{connection[:vpn_connection_id]}",
|
30
|
+
vpn_connection_id: connection[:vpn_connection_id]
|
31
|
+
}
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
########################################################################
|
2
|
+
# AwsVpnGateway is the +aws_vpn_gateway+ terrform resource,
|
3
|
+
#
|
4
|
+
# {https://www.terraform.io/docs/providers/aws/r/vpn_gateway.html Terraform Docs}
|
5
|
+
########################################################################
|
6
|
+
class GeoEngineer::Resources::AwsVpnGateway < GeoEngineer::Resource
|
7
|
+
validate -> { validate_has_tag(:Name) }
|
8
|
+
|
9
|
+
after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
|
10
|
+
after :initialize, -> { _geo_id -> { NullObject.maybe(tags)[:Name] } }
|
11
|
+
|
12
|
+
def self._fetch_remote_resources
|
13
|
+
AwsClients.ec2.describe_vpn_gateways['vpn_gateways'].map(&:to_h).map do |gateway|
|
14
|
+
gateway.merge(
|
15
|
+
{
|
16
|
+
_terraform_id: gateway[:vpn_gateway_id],
|
17
|
+
_geo_id: gateway[:tags]&.find { |tag| tag[:key] == "Name" }&.dig(:value)
|
18
|
+
}
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
########################################################################
|
2
|
+
# AwsVpnGatewayAttachment is the +aws_vpn_gateway_attachment+ terrform resource,
|
3
|
+
#
|
4
|
+
# {https://www.terraform.io/docs/providers/aws/r/vpn_gateway_attachment.html Terraform Docs}
|
5
|
+
########################################################################
|
6
|
+
class GeoEngineer::Resources::AwsVpnGatewayAttachment < GeoEngineer::Resource
|
7
|
+
validate -> { validate_required_attributes([:vpc_id, :vpn_gateway_id]) }
|
8
|
+
|
9
|
+
after :initialize, -> {
|
10
|
+
_terraform_id -> { "vpn-attachment-#{Crc32.hashcode(vpc_id + '-' + vpn_gateway_id)}" }
|
11
|
+
}
|
12
|
+
after :initialize, -> { _geo_id -> { "#{vpc_id}::#{vpn_gateway_id}" } }
|
13
|
+
|
14
|
+
def support_tags?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def self._fetch_remote_resources
|
19
|
+
AwsClients
|
20
|
+
.ec2
|
21
|
+
.describe_vpn_gateways['vpn_gateways']
|
22
|
+
.map(&:to_h)
|
23
|
+
.select { |gateway| !gateway[:vpc_attachments].empty? }
|
24
|
+
.map { |gateway| _generate_attachment(gateway) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self._generate_attachment(gateway)
|
28
|
+
# Terraform ID generation via:
|
29
|
+
# https://github.com/hashicorp/terraform/blob/master/builtin/providers/aws/resource_aws_vpn_gateway_attachment.go#L209
|
30
|
+
vpc_id = gateway[:vpc_attachments].first[:vpc_id]
|
31
|
+
id_string = "#{vpc_id}-#{gateway[:vpn_gateway_id]}"
|
32
|
+
terraform_id = "vpn-attachment-#{Crc32.hashcode(id_string)}"
|
33
|
+
|
34
|
+
{
|
35
|
+
_terraform_id: terraform_id,
|
36
|
+
_geo_id: "#{vpc_id}::#{gateway[:vpn_gateway_id]}",
|
37
|
+
vpn_gateway_id: gateway[:vpn_gateway_id],
|
38
|
+
vpc_id: vpc_id
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
data/lib/geoengineer/template.rb
CHANGED
@@ -5,21 +5,37 @@ class GeoEngineer::Template
|
|
5
5
|
include HasAttributes
|
6
6
|
include HasResources
|
7
7
|
|
8
|
-
def initialize(name,
|
9
|
-
@project = project
|
8
|
+
def initialize(name, parent, parameters = {})
|
10
9
|
@name = name
|
11
|
-
|
10
|
+
case parent
|
11
|
+
when GeoEngineer::Project then add_project_attributes(parent)
|
12
|
+
when GeoEngineer::Environment then add_env_attributes(parent)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Helper method to accomodate different parents
|
17
|
+
def add_project_attributes(project)
|
18
|
+
@project = project
|
19
|
+
@environment = project.environment
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_env_attributes(environment)
|
23
|
+
@environment = environment
|
12
24
|
end
|
13
25
|
|
14
26
|
def resource(type, id, &block)
|
15
27
|
return find_resource(type, id) unless block_given?
|
16
28
|
resource = create_resource(type, id, &block)
|
17
29
|
resource.template = self
|
18
|
-
resource.project = @project
|
19
30
|
resource.environment = @environment
|
31
|
+
resource.project = @project if @project
|
20
32
|
resource
|
21
33
|
end
|
22
34
|
|
35
|
+
def all_resources
|
36
|
+
resources
|
37
|
+
end
|
38
|
+
|
23
39
|
# The resources that are passed to the block on instantiation
|
24
40
|
# This can be overridden to specify the order of the templates resources
|
25
41
|
def template_resources
|
@@ -0,0 +1,61 @@
|
|
1
|
+
########################################################################
|
2
|
+
# Crc32 is a pure ruby implementation of CRC32. Copied from:
|
3
|
+
# - http://www.codeography.com/2009/05/22/pure-ruby-crc32-adccp-pkzip.html
|
4
|
+
# - https://github.com/postmodern/digest-crc/blob/master/lib/digest/crc32.rb
|
5
|
+
########################################################################
|
6
|
+
class Crc32
|
7
|
+
CRC_TABLE = [
|
8
|
+
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
9
|
+
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
10
|
+
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
11
|
+
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
12
|
+
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
13
|
+
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
14
|
+
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
15
|
+
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
16
|
+
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
17
|
+
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
18
|
+
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
19
|
+
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
20
|
+
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
21
|
+
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
22
|
+
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
23
|
+
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
24
|
+
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
25
|
+
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
26
|
+
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
27
|
+
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
28
|
+
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
29
|
+
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
30
|
+
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
31
|
+
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
32
|
+
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
33
|
+
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
34
|
+
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
35
|
+
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
36
|
+
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
37
|
+
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
38
|
+
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
39
|
+
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
40
|
+
].freeze
|
41
|
+
|
42
|
+
INIT_CRC = 0xffffffff
|
43
|
+
|
44
|
+
XOR_MASK = 0xffffffff
|
45
|
+
|
46
|
+
def self.checksum(string, crc = INIT_CRC)
|
47
|
+
string.each_byte do |byte|
|
48
|
+
crc = (((crc >> 8) & 0x00ffffff) ^ CRC_TABLE[(crc ^ byte) & 0xff])
|
49
|
+
end
|
50
|
+
crc ^ XOR_MASK
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.hashcode(string)
|
54
|
+
return 0 unless string
|
55
|
+
|
56
|
+
value = checksum(string).to_i
|
57
|
+
return value if value >= 0
|
58
|
+
return -value if value <= 0
|
59
|
+
0
|
60
|
+
end
|
61
|
+
end
|
@@ -3,8 +3,12 @@
|
|
3
3
|
########################################################################
|
4
4
|
module HasAttributes
|
5
5
|
def attributes
|
6
|
-
@_attributes
|
7
|
-
|
6
|
+
@_attributes ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
# Contains the procs used to calculate attributes
|
10
|
+
def attribute_procs
|
11
|
+
@_procs ||= {}
|
8
12
|
end
|
9
13
|
|
10
14
|
def [](key)
|
@@ -27,20 +31,30 @@ module HasAttributes
|
|
27
31
|
# this is a setter
|
28
32
|
name = name[0...-1] if name.end_with?"="
|
29
33
|
val = args.length == 1 ? args[0] : args
|
34
|
+
attribute_procs[name] = val if val.is_a?(Proc)
|
30
35
|
attributes[name] = val
|
31
|
-
val
|
32
36
|
end
|
33
37
|
|
34
38
|
def retrieve_attribute(name)
|
35
39
|
# this is a getter
|
36
|
-
val = attributes
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
val = if attributes.key?(name)
|
41
|
+
attributes[name]
|
42
|
+
else
|
43
|
+
attribute_missing(name)
|
44
|
+
end
|
45
|
+
return val unless val.is_a?(Proc)
|
46
|
+
attributes[name] = val.call() # cache the value to override the Proc
|
47
|
+
end
|
48
|
+
|
49
|
+
# For any value that has been lazily calculated, recalculate it
|
50
|
+
def reset_attributes
|
51
|
+
attribute_procs.each { |name, function| attributes[name] = function }
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def eager_load_attributes
|
56
|
+
attribute_procs.each { |name, function| attributes[name] = function.call() }
|
57
|
+
self
|
44
58
|
end
|
45
59
|
|
46
60
|
def attribute_missing(name)
|