axle_attributes 1.13.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.travis.yml +16 -0
- data/Gemfile +15 -0
- data/README.md +10 -0
- data/Rakefile +18 -0
- data/app/models/attribute_customization.rb +7 -0
- data/app/models/attribute_customization/local_cache.rb +28 -0
- data/app/models/attribute_mapping.rb +15 -0
- data/app/models/attribute_mapping/local_cache.rb +40 -0
- data/axle_attributes.gemspec +22 -0
- data/bin/rails +8 -0
- data/db/migrate/20131118042651_create_attribute_customizations.rb +16 -0
- data/db/migrate/20131121013237_create_attribute_mappings.rb +17 -0
- data/db/migrate/20151120160522_add_editable_to_attribute_customizations.rb +7 -0
- data/lib/axle_attributes.rb +30 -0
- data/lib/axle_attributes/child_definition.rb +42 -0
- data/lib/axle_attributes/conversions.rb +36 -0
- data/lib/axle_attributes/definition.rb +118 -0
- data/lib/axle_attributes/definition/callbacks.rb +34 -0
- data/lib/axle_attributes/definition/customization.rb +51 -0
- data/lib/axle_attributes/definition/formatted.rb +57 -0
- data/lib/axle_attributes/definition/indexed.rb +41 -0
- data/lib/axle_attributes/definition/mappings.rb +48 -0
- data/lib/axle_attributes/dumper.rb +54 -0
- data/lib/axle_attributes/engine.rb +4 -0
- data/lib/axle_attributes/format.rb +74 -0
- data/lib/axle_attributes/has_attributes.rb +104 -0
- data/lib/axle_attributes/has_attributes/json_reader.rb +87 -0
- data/lib/axle_attributes/model.rb +34 -0
- data/lib/axle_attributes/null_definition.rb +11 -0
- data/lib/axle_attributes/parent_definition.rb +37 -0
- data/lib/axle_attributes/provided.rb +67 -0
- data/lib/axle_attributes/regex.rb +4 -0
- data/lib/axle_attributes/segmented.rb +30 -0
- data/lib/axle_attributes/serializations.rb +147 -0
- data/lib/axle_attributes/serializations/builder/serialization.rb +83 -0
- data/lib/axle_attributes/serializations/builder/serialize_many.rb +17 -0
- data/lib/axle_attributes/serializations/builder/serialize_one.rb +7 -0
- data/lib/axle_attributes/serializations/reflection.rb +40 -0
- data/lib/axle_attributes/serializations/serialization.rb +88 -0
- data/lib/axle_attributes/serializations/serialize_many.rb +88 -0
- data/lib/axle_attributes/serializations/serialize_one.rb +34 -0
- data/lib/axle_attributes/serialized_child.rb +58 -0
- data/lib/axle_attributes/validations.rb +29 -0
- data/lib/axle_attributes/versioned.rb +21 -0
- data/test/dummy/README.rdoc +6 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.keep +0 -0
- data/test/dummy/app/models/.keep +0 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +12 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +13 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +38 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/db/schema.rb +50 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/factories/all.rb +14 -0
- data/test/helper.rb +25 -0
- data/test/lib/child_definition_test.rb +43 -0
- data/test/lib/conversions_test.rb +39 -0
- data/test/lib/definition/customization_test.rb +36 -0
- data/test/lib/definition/formatted_test.rb +75 -0
- data/test/lib/definition/indexed_test.rb +57 -0
- data/test/lib/definition/mappings_test.rb +26 -0
- data/test/lib/definition_test.rb +84 -0
- data/test/lib/dumper_test.rb +38 -0
- data/test/lib/format_test.rb +64 -0
- data/test/lib/has_attributes/json_reader_test.rb +46 -0
- data/test/lib/has_attributes_test.rb +69 -0
- data/test/lib/model_test.rb +44 -0
- data/test/lib/null_definition_test.rb +27 -0
- data/test/lib/parent_definition_test.rb +75 -0
- data/test/lib/provided_test.rb +46 -0
- data/test/lib/segmented_test.rb +27 -0
- data/test/lib/serializations/reflection_test.rb +24 -0
- data/test/lib/serializations/serialize_many_test.rb +194 -0
- data/test/lib/serializations/serialize_one_test.rb +122 -0
- data/test/lib/serializations_test.rb +24 -0
- data/test/lib/serialized_child_test.rb +91 -0
- data/test/lib/timestamp_attributes_test.rb +14 -0
- data/test/lib/validations_test.rb +8 -0
- data/test/lib/versioned_test.rb +35 -0
- data/test/models/attribute_customization/local_cache_test.rb +16 -0
- data/test/models/attribute_customization_test.rb +8 -0
- data/test/models/attribute_mapping/local_cache_test.rb +31 -0
- data/test/models/attribute_mapping_test.rb +20 -0
- data/test/support/business.rb +22 -0
- data/test/support/pg.rb +9 -0
- data/test/support/vegetable.rb +8 -0
- metadata +215 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module AxleAttributes
|
2
|
+
class Definition
|
3
|
+
# Adds support for +setup+ and +teardown+ callbacks.
|
4
|
+
# These callbacks serve as a replacement to overwriting the
|
5
|
+
# <tt>#setup</tt> and <tt>#teardown</tt> methods of your TestCase.
|
6
|
+
#
|
7
|
+
# class ExampleTest < ActiveSupport::TestCase
|
8
|
+
# setup do
|
9
|
+
# # ...
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
module Callbacks
|
13
|
+
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
included do
|
17
|
+
include ActiveSupport::Callbacks
|
18
|
+
define_callbacks :setup
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
# Add a callback, which runs before <tt>TestCase#setup</tt>.
|
23
|
+
def setup(*args, &block)
|
24
|
+
set_callback(:setup, :before, *args, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def before_setup # :nodoc:
|
29
|
+
super
|
30
|
+
run_callbacks :setup
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module AxleAttributes
|
2
|
+
class Definition
|
3
|
+
module Customization
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :cached_customizations
|
8
|
+
self.cached_customizations = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def cached_customization_for(namespace)
|
13
|
+
cached_customizations[namespace] ||= AttributeCustomization.namespace_cache_for(namespace).read
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def customization
|
18
|
+
self.class.cached_customization_for(namespace)[name]
|
19
|
+
end
|
20
|
+
|
21
|
+
def display_name
|
22
|
+
read_customization(:display_name) || name.titlecase.gsub('.', ' ')
|
23
|
+
end
|
24
|
+
|
25
|
+
def description
|
26
|
+
read_customization :description
|
27
|
+
end
|
28
|
+
|
29
|
+
def notes
|
30
|
+
read_customization :notes
|
31
|
+
end
|
32
|
+
|
33
|
+
def editable_customization
|
34
|
+
value = customization.try(:editable)
|
35
|
+
value.nil? ? true : value
|
36
|
+
end
|
37
|
+
|
38
|
+
def deprecated_on
|
39
|
+
read_customization :deprecated_on
|
40
|
+
end
|
41
|
+
|
42
|
+
def deprecated?
|
43
|
+
deprecated_on.present?
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_customization(property)
|
47
|
+
customization.try(property).presence
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module AxleAttributes
|
2
|
+
class Definition
|
3
|
+
module Formatted
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :formatters
|
8
|
+
self.formatters = {}
|
9
|
+
|
10
|
+
setup do
|
11
|
+
setup_method_override!
|
12
|
+
formatter.try(:setup!, self)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def analyzer_mapping
|
17
|
+
if mapping = formatter.try(:analyzer_mapping)
|
18
|
+
mapping
|
19
|
+
else
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def instructions
|
25
|
+
fetch_format_property(:instructions)
|
26
|
+
end
|
27
|
+
|
28
|
+
def standardize(value)
|
29
|
+
formatter.try(:standardize, self, value) || value
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate(value)
|
33
|
+
formatter.try :validate, self, value
|
34
|
+
end
|
35
|
+
|
36
|
+
def formatter
|
37
|
+
formatters[format]
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def fetch_format_property(property)
|
43
|
+
read_customization(property) || formatter.try(property, self)
|
44
|
+
end
|
45
|
+
|
46
|
+
def setup_method_override!
|
47
|
+
if formatter.respond_to?(:standardize)
|
48
|
+
definition = self
|
49
|
+
model.send :define_method, "#{name}=" do |value|
|
50
|
+
super definition.standardize(value)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module AxleAttributes
|
2
|
+
class Definition
|
3
|
+
module Indexed
|
4
|
+
def index
|
5
|
+
options[:index]
|
6
|
+
end
|
7
|
+
|
8
|
+
ANALYZERS = [:snowball, :proper_noun, :simple]
|
9
|
+
def analyzer_mapping
|
10
|
+
{type: 'string', analyzer: index} if ANALYZERS.include?(index)
|
11
|
+
end
|
12
|
+
|
13
|
+
INDEXES_BY_TYPE = {
|
14
|
+
array: {type: "string", index: "not_analyzed", doc_values: true},
|
15
|
+
boolean: {type: "boolean", doc_values: true},
|
16
|
+
float: {type: "double", doc_values: true},
|
17
|
+
integer: {type: "long", doc_values: true},
|
18
|
+
json: {type: "boolean"},
|
19
|
+
string: {type: 'string', index_analyzer: 'keyword', search_analyzer: 'standard'},
|
20
|
+
text: {type: 'string', index_analyzer: 'keyword', search_analyzer: 'standard'},
|
21
|
+
time: {type: "date", format: "dateOptionalTime", doc_values: true},
|
22
|
+
date: {type: "date", format: "date", doc_values: true}
|
23
|
+
}
|
24
|
+
def index_mapping
|
25
|
+
return unless index
|
26
|
+
|
27
|
+
if mapping = analyzer_mapping
|
28
|
+
multi_field_index(name, mapping)
|
29
|
+
elsif index == true
|
30
|
+
INDEXES_BY_TYPE[type] || (raise "unknown index type #{type.inspect} for #{name}")
|
31
|
+
elsif index.is_a?(Hash)
|
32
|
+
index
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def multi_field_index(field, analyzer_mapping)
|
37
|
+
{type: "multi_field", fields: {field => {type: "string", index: "not_analyzed", doc_values: true}, analyzed: analyzer_mapping}}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module AxleAttributes
|
2
|
+
class Definition
|
3
|
+
module Mappings
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :cached_attribute_mappings
|
8
|
+
self.cached_attribute_mappings = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def cached_attribute_mappings_for(namespace)
|
13
|
+
cached_attribute_mappings[namespace] ||= AttributeMapping.cached_mapping_for(namespace).read
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_options
|
18
|
+
mappings.map do |k, v|
|
19
|
+
[v, k]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def mappings
|
24
|
+
if @mappings
|
25
|
+
@mappings
|
26
|
+
elsif mapping_model && mapping_model.respond_to?(:cached_mapping)
|
27
|
+
mapping_model.cached_mapping
|
28
|
+
else
|
29
|
+
self.class.cached_attribute_mappings_for(namespace)[name] || {}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def mappings=(val)
|
34
|
+
@mappings = val
|
35
|
+
end
|
36
|
+
|
37
|
+
def mapping_records
|
38
|
+
AttributeMapping.where(namespace: namespace, attribute_name: name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def mapping_model
|
42
|
+
if options[:mapping_model]
|
43
|
+
@mapping_model ||= options[:mapping_model].constantize
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module AxleAttributes
|
4
|
+
class Dumper
|
5
|
+
attr_reader :model
|
6
|
+
def initialize(model)
|
7
|
+
@model = model
|
8
|
+
end
|
9
|
+
|
10
|
+
def dump_internal
|
11
|
+
dump(model.attribute_set, ["Attribute", "Display Name", "Type", "Deprecation", "Legacy Name", "Mapping", "Description", "Note"]) do |definition|
|
12
|
+
[
|
13
|
+
definition.canonical_name,
|
14
|
+
definition.display_name,
|
15
|
+
definition.type,
|
16
|
+
definition.deprecated_on ? definition.deprecated_on.to_s('%Y/%m/%d') : nil,
|
17
|
+
definition.options[:mmdb_name],
|
18
|
+
mapping_display(definition),
|
19
|
+
definition.description,
|
20
|
+
definition.notes
|
21
|
+
]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def dump_public(attribute_set)
|
26
|
+
dump(attribute_set, ["Attribute", "Display Name", "Type", "Description"]) do |definition|
|
27
|
+
[
|
28
|
+
definition.canonical_name,
|
29
|
+
definition.display_name,
|
30
|
+
definition.type,
|
31
|
+
definition.description
|
32
|
+
]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def dump(attribute_set, headers)
|
37
|
+
CSV.generate(headers: headers, write_headers: true) do |csv|
|
38
|
+
attribute_set.sort.each do |attribute_name|
|
39
|
+
definition = model.attributes[attribute_name]
|
40
|
+
csv << yield(definition) if definition
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def mapping_display(definition)
|
46
|
+
if mapping_model = definition.mapping_model
|
47
|
+
"#{mapping_model.model_name.plural}.#{mapping_model.natural_key}" if mapping_model.respond_to?(:natural_key)
|
48
|
+
elsif definition.mappings.any?
|
49
|
+
"attribute_mappings"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module AxleAttributes
|
2
|
+
class Format
|
3
|
+
class_attribute :phone_regex
|
4
|
+
self.phone_regex = /\A\(\d{3}\) \d{3}-\d{4}\z/
|
5
|
+
|
6
|
+
class_attribute :url_regex
|
7
|
+
self.url_regex = /\A(https?:\/\/)([-a-z0-9]+\.[-.a-z0-9:]+)(\/[^\s]+)?\z/
|
8
|
+
|
9
|
+
class_attribute :zip_regex
|
10
|
+
self.zip_regex = /\A\d{5}\z/
|
11
|
+
|
12
|
+
class_attribute :postal_code_regex
|
13
|
+
self.postal_code_regex = /\A(\d{5}(-\d{4})?|[A-Z0-9]{6})\z/
|
14
|
+
|
15
|
+
class << self
|
16
|
+
PHONEWORDS = {"A"=>"2", "B"=>"2", "C"=>"2", "D"=>"3", "E"=>"3", "F"=>"3", "G"=>"4", "H"=>"4", "I"=>"4", "J"=>"5",
|
17
|
+
"K"=>"5", "L"=>"5", "M"=>"6", "N"=>"6", "O"=>"6", "P"=>"7", "Q"=>"7", "R"=>"7", "S"=>"7", "T"=>"8",
|
18
|
+
"U"=>"8", "V"=>"8", "W"=>"9", "X"=>"9", "Y"=>"9", "Z"=>"9"}
|
19
|
+
|
20
|
+
def standardize_phone(phone)
|
21
|
+
standardize phone, self.phone_regex do
|
22
|
+
standardized = phone.chars.map { |char| PHONEWORDS[char.upcase] || char }.join('')
|
23
|
+
|
24
|
+
standardized.gsub!(/\D/, '')
|
25
|
+
|
26
|
+
if standardized.size == 10
|
27
|
+
standardized.gsub!(/(\d{3})(\d{3})(\d{4})/, "(\\1) \\2-\\3")
|
28
|
+
standardized
|
29
|
+
elsif standardized.size == 11 && standardized[0] == '1'
|
30
|
+
standardized.gsub!(/1(\d{3})(\d{3})(\d{4})/, "(\\1) \\2-\\3")
|
31
|
+
standardized
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def standardize_postal_code(postal_code)
|
37
|
+
standardize postal_code, postal_code_regex do
|
38
|
+
standardized = postal_code.remove(/[^\-[:alnum:]]/)
|
39
|
+
case standardized.length
|
40
|
+
when 6 then standardized.upcase!
|
41
|
+
when 9 then standardized.sub!(/\A(\d{5})(\d{4})\z/, '\\1-\\2')
|
42
|
+
end
|
43
|
+
|
44
|
+
standardized
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def standardize_url(website)
|
49
|
+
standardize website, self.url_regex do
|
50
|
+
if website =~ /^(\w*):\/\//
|
51
|
+
scheme, _, resource = website.partition("://")
|
52
|
+
scheme.downcase!
|
53
|
+
else
|
54
|
+
scheme = "http"
|
55
|
+
resource = website
|
56
|
+
end
|
57
|
+
resource.strip!
|
58
|
+
|
59
|
+
host, slash, path = resource.partition("/")
|
60
|
+
host.downcase!
|
61
|
+
path.gsub! ' ', '%20'
|
62
|
+
|
63
|
+
path.empty? ? "#{scheme}://#{host}" : "#{scheme}://#{host}/#{path}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def standardize(value, regex)
|
68
|
+
return value if value.blank? || value =~ regex
|
69
|
+
standardized = yield(value)
|
70
|
+
standardized =~ regex ? standardized : value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'axle_attributes/has_attributes/json_reader'
|
2
|
+
require 'open-uri'
|
3
|
+
|
4
|
+
module AxleAttributes
|
5
|
+
module HasAttributes
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :has_attribute_definition_class
|
10
|
+
self.has_attribute_definition_class = '::AxleAttributes::Definition'
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def inherited(child)
|
15
|
+
child.attribute_set = attribute_set.dup
|
16
|
+
child.attributes = attributes.dup
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
# Example:
|
21
|
+
# has_attributes(
|
22
|
+
# color: {type: :string, index: true, version: true},
|
23
|
+
# weight: {type: :integer, version: true}
|
24
|
+
# )
|
25
|
+
def has_attributes(definitions, default_options = {})
|
26
|
+
definitions.each do |name, options|
|
27
|
+
has_attribute name, default_options.merge(options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_attribute(name, options = {})
|
32
|
+
name = name.to_s
|
33
|
+
definition = attribute_definition_class.new(self, name, options)
|
34
|
+
add_attribute_definition(name, definition)
|
35
|
+
definition.setup!
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_attribute_definition(name, definition)
|
39
|
+
attributes[name] = definition
|
40
|
+
attribute_set << name
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_mappings(mappings_hash)
|
44
|
+
mappings_hash.each do |name, mappings|
|
45
|
+
has_mapping name, mappings
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def has_mapping(name, mappings)
|
50
|
+
if mappings.is_a?(Array)
|
51
|
+
mappings = Hash[mappings.map { |v| [v, v.humanize] }]
|
52
|
+
end
|
53
|
+
|
54
|
+
attributes[name.to_s].mappings = mappings
|
55
|
+
end
|
56
|
+
|
57
|
+
def attributes_file_root
|
58
|
+
@attributes_file_root ||= Rails.root.join('db', 'attributes')
|
59
|
+
end
|
60
|
+
|
61
|
+
def attributes_file_root=(pathname)
|
62
|
+
pathname = Pathname.new(pathname) unless pathname.is_a?(Pathname)
|
63
|
+
@attributes_file_root = pathname
|
64
|
+
end
|
65
|
+
|
66
|
+
def has_attributes_file(filename, options = {})
|
67
|
+
options[:defaults] ||= {}
|
68
|
+
options[:defaults][:filename] = filename
|
69
|
+
AxleAttributes::HasAttributes::JsonReader.read_definitions(self, read_attributes_file(filename), options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def attributes
|
73
|
+
@attributes ||= {}
|
74
|
+
end
|
75
|
+
|
76
|
+
def attributes=(attributes)
|
77
|
+
@attributes = attributes
|
78
|
+
end
|
79
|
+
|
80
|
+
def attribute_set
|
81
|
+
@attribute_set ||= Set.new
|
82
|
+
end
|
83
|
+
|
84
|
+
def attribute_set=(attribute_set)
|
85
|
+
@attribute_set = attribute_set
|
86
|
+
end
|
87
|
+
|
88
|
+
def attribute_definition_class
|
89
|
+
@attribute_definition_class ||= has_attribute_definition_class.constantize
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def read_attributes_file(filename)
|
95
|
+
attributes_file_pathname(filename).read
|
96
|
+
end
|
97
|
+
|
98
|
+
def attributes_file_pathname(filename)
|
99
|
+
attributes_file_root.join("#{filename}.json")
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|