axle_attributes 1.13.2

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.
Files changed (119) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.travis.yml +16 -0
  4. data/Gemfile +15 -0
  5. data/README.md +10 -0
  6. data/Rakefile +18 -0
  7. data/app/models/attribute_customization.rb +7 -0
  8. data/app/models/attribute_customization/local_cache.rb +28 -0
  9. data/app/models/attribute_mapping.rb +15 -0
  10. data/app/models/attribute_mapping/local_cache.rb +40 -0
  11. data/axle_attributes.gemspec +22 -0
  12. data/bin/rails +8 -0
  13. data/db/migrate/20131118042651_create_attribute_customizations.rb +16 -0
  14. data/db/migrate/20131121013237_create_attribute_mappings.rb +17 -0
  15. data/db/migrate/20151120160522_add_editable_to_attribute_customizations.rb +7 -0
  16. data/lib/axle_attributes.rb +30 -0
  17. data/lib/axle_attributes/child_definition.rb +42 -0
  18. data/lib/axle_attributes/conversions.rb +36 -0
  19. data/lib/axle_attributes/definition.rb +118 -0
  20. data/lib/axle_attributes/definition/callbacks.rb +34 -0
  21. data/lib/axle_attributes/definition/customization.rb +51 -0
  22. data/lib/axle_attributes/definition/formatted.rb +57 -0
  23. data/lib/axle_attributes/definition/indexed.rb +41 -0
  24. data/lib/axle_attributes/definition/mappings.rb +48 -0
  25. data/lib/axle_attributes/dumper.rb +54 -0
  26. data/lib/axle_attributes/engine.rb +4 -0
  27. data/lib/axle_attributes/format.rb +74 -0
  28. data/lib/axle_attributes/has_attributes.rb +104 -0
  29. data/lib/axle_attributes/has_attributes/json_reader.rb +87 -0
  30. data/lib/axle_attributes/model.rb +34 -0
  31. data/lib/axle_attributes/null_definition.rb +11 -0
  32. data/lib/axle_attributes/parent_definition.rb +37 -0
  33. data/lib/axle_attributes/provided.rb +67 -0
  34. data/lib/axle_attributes/regex.rb +4 -0
  35. data/lib/axle_attributes/segmented.rb +30 -0
  36. data/lib/axle_attributes/serializations.rb +147 -0
  37. data/lib/axle_attributes/serializations/builder/serialization.rb +83 -0
  38. data/lib/axle_attributes/serializations/builder/serialize_many.rb +17 -0
  39. data/lib/axle_attributes/serializations/builder/serialize_one.rb +7 -0
  40. data/lib/axle_attributes/serializations/reflection.rb +40 -0
  41. data/lib/axle_attributes/serializations/serialization.rb +88 -0
  42. data/lib/axle_attributes/serializations/serialize_many.rb +88 -0
  43. data/lib/axle_attributes/serializations/serialize_one.rb +34 -0
  44. data/lib/axle_attributes/serialized_child.rb +58 -0
  45. data/lib/axle_attributes/validations.rb +29 -0
  46. data/lib/axle_attributes/versioned.rb +21 -0
  47. data/test/dummy/README.rdoc +6 -0
  48. data/test/dummy/Rakefile +6 -0
  49. data/test/dummy/app/assets/images/.keep +0 -0
  50. data/test/dummy/app/assets/javascripts/application.js +13 -0
  51. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  52. data/test/dummy/app/controllers/application_controller.rb +5 -0
  53. data/test/dummy/app/controllers/concerns/.keep +0 -0
  54. data/test/dummy/app/helpers/application_helper.rb +2 -0
  55. data/test/dummy/app/mailers/.keep +0 -0
  56. data/test/dummy/app/models/.keep +0 -0
  57. data/test/dummy/app/models/concerns/.keep +0 -0
  58. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  59. data/test/dummy/bin/bundle +3 -0
  60. data/test/dummy/bin/rails +4 -0
  61. data/test/dummy/bin/rake +4 -0
  62. data/test/dummy/config.ru +4 -0
  63. data/test/dummy/config/application.rb +12 -0
  64. data/test/dummy/config/boot.rb +5 -0
  65. data/test/dummy/config/database.yml +13 -0
  66. data/test/dummy/config/environment.rb +5 -0
  67. data/test/dummy/config/environments/development.rb +29 -0
  68. data/test/dummy/config/environments/production.rb +80 -0
  69. data/test/dummy/config/environments/test.rb +38 -0
  70. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  71. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  72. data/test/dummy/config/initializers/inflections.rb +16 -0
  73. data/test/dummy/config/initializers/mime_types.rb +5 -0
  74. data/test/dummy/config/initializers/secret_token.rb +12 -0
  75. data/test/dummy/config/initializers/session_store.rb +3 -0
  76. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  77. data/test/dummy/config/locales/en.yml +23 -0
  78. data/test/dummy/config/routes.rb +56 -0
  79. data/test/dummy/db/schema.rb +50 -0
  80. data/test/dummy/lib/assets/.keep +0 -0
  81. data/test/dummy/log/.keep +0 -0
  82. data/test/dummy/public/404.html +58 -0
  83. data/test/dummy/public/422.html +58 -0
  84. data/test/dummy/public/500.html +57 -0
  85. data/test/dummy/public/favicon.ico +0 -0
  86. data/test/factories/all.rb +14 -0
  87. data/test/helper.rb +25 -0
  88. data/test/lib/child_definition_test.rb +43 -0
  89. data/test/lib/conversions_test.rb +39 -0
  90. data/test/lib/definition/customization_test.rb +36 -0
  91. data/test/lib/definition/formatted_test.rb +75 -0
  92. data/test/lib/definition/indexed_test.rb +57 -0
  93. data/test/lib/definition/mappings_test.rb +26 -0
  94. data/test/lib/definition_test.rb +84 -0
  95. data/test/lib/dumper_test.rb +38 -0
  96. data/test/lib/format_test.rb +64 -0
  97. data/test/lib/has_attributes/json_reader_test.rb +46 -0
  98. data/test/lib/has_attributes_test.rb +69 -0
  99. data/test/lib/model_test.rb +44 -0
  100. data/test/lib/null_definition_test.rb +27 -0
  101. data/test/lib/parent_definition_test.rb +75 -0
  102. data/test/lib/provided_test.rb +46 -0
  103. data/test/lib/segmented_test.rb +27 -0
  104. data/test/lib/serializations/reflection_test.rb +24 -0
  105. data/test/lib/serializations/serialize_many_test.rb +194 -0
  106. data/test/lib/serializations/serialize_one_test.rb +122 -0
  107. data/test/lib/serializations_test.rb +24 -0
  108. data/test/lib/serialized_child_test.rb +91 -0
  109. data/test/lib/timestamp_attributes_test.rb +14 -0
  110. data/test/lib/validations_test.rb +8 -0
  111. data/test/lib/versioned_test.rb +35 -0
  112. data/test/models/attribute_customization/local_cache_test.rb +16 -0
  113. data/test/models/attribute_customization_test.rb +8 -0
  114. data/test/models/attribute_mapping/local_cache_test.rb +31 -0
  115. data/test/models/attribute_mapping_test.rb +20 -0
  116. data/test/support/business.rb +22 -0
  117. data/test/support/pg.rb +9 -0
  118. data/test/support/vegetable.rb +8 -0
  119. metadata +215 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d25fdf60b1d16bd313d249594d4347b277dd304e
4
+ data.tar.gz: 5bb4786bc0b1e5ad172fbaf743077fabd08d4fc1
5
+ SHA512:
6
+ metadata.gz: 23b04c254bbc1003e231301531ea18e78a89d3b8986391927fe79abb037b2c53282aefa4e2a9370502502d53bc9f4b349b1c6bca9e22b33e17c880dfe8d07160
7
+ data.tar.gz: a7d1c499bda8c070077a5318493ad16f731dd300eff0aa8595e487fa9ccc96fb958c2921b3fe211320d499e6d1266a1da4cf605a5168e864e0f954f555b9ec37
@@ -0,0 +1,4 @@
1
+ Gemfile.lock
2
+ log/*.log
3
+ test/dummy/log/*.log
4
+ test/dummy/tmp
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+ rvm: 2.2.2
3
+ sudo: false
4
+ cache: bundler
5
+ addons:
6
+ postgresql: '9.4'
7
+ env:
8
+ global:
9
+ secure: KODrG44n8gXbtBJc+8U2KtMsVlG/SLgddpR2AquKbYI/ZKe1xsTkb79Qdnh1jBVWdVcUb1DCbxnPH7dt9aoAsiqwZdqc9Tz87EAFv3vM0EnGITBUWM5glsohBriE1+c8kZRh/9ciH4c+SvnwyJKQe/ON9I+He6o+luyZVxvBEQg=
10
+
11
+ before_script:
12
+ - bundle exec rake app:db:setup
13
+
14
+ after_success:
15
+ - if [[ -n "$TRAVIS_TAG" ]]; then export GEM_FILENAME=$(gem build axle_attributes.gemspec | grep File | awk '{print $2}'); fi
16
+ - if [[ -n "$TRAVIS_TAG" ]]; then curl -F package=@$GEM_FILENAME $GEMFURY_REPO; fi
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ gemspec
2
+
3
+ gem 'superstore', github: 'data-axle/superstore'
4
+
5
+ source 'http://rubygems.org' do
6
+ group :test do
7
+ gem 'rake'
8
+ gem 'pg'
9
+ gem 'factory_girl'
10
+ end
11
+ end
12
+
13
+ source 'https://Wp3MVhqmqjJmqddBEsSG@repo.fury.io/dataaxle' do
14
+ gem 'axle_traveller'
15
+ end
@@ -0,0 +1,10 @@
1
+ ### Installation ###
2
+ ```
3
+ rake axle_attributes_engine:install:migrations
4
+ ```
5
+
6
+ ### Running tests ###
7
+ ```
8
+ rake db:create
9
+ rake
10
+ ```
@@ -0,0 +1,18 @@
1
+ require 'bundler/setup'
2
+
3
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
4
+ load 'rails/tasks/engine.rake'
5
+
6
+ Bundler::GemHelper.install_tasks
7
+
8
+ desc 'Default: run unit tests.'
9
+ task default: :test
10
+
11
+ require 'rake/testtask'
12
+ desc 'Test.'
13
+ Rake::TestTask.new(:test) do |t|
14
+ t.libs << 'lib'
15
+ t.libs << 'test'
16
+ t.pattern = 'test/**/*_test.rb'
17
+ t.verbose = true
18
+ end
@@ -0,0 +1,7 @@
1
+ class AttributeCustomization < ActiveRecord::Base
2
+ include AttributeCustomization::LocalCache
3
+
4
+ def aliases
5
+ self.aliases_csv.try(:split, ',') || []
6
+ end
7
+ end
@@ -0,0 +1,28 @@
1
+ class AttributeCustomization
2
+ module LocalCache
3
+ class NamespaceCache < Struct.new(:namespace)
4
+ include Traveller::LocalCache
5
+
6
+ def fetch_value
7
+ AttributeCustomization.where(namespace: namespace).index_by(&:name)
8
+ end
9
+
10
+ def cache_name
11
+ "attribute_customizations_#{namespace}"
12
+ end
13
+ end
14
+
15
+ extend ActiveSupport::Concern
16
+
17
+ included do
18
+ after_save { self.class.namespace_cache_for(namespace).expire! }
19
+ after_destroy { self.class.namespace_cache_for(namespace).expire! }
20
+ end
21
+
22
+ module ClassMethods
23
+ def namespace_cache_for(namespace)
24
+ (@namespace_cache ||= {})[namespace] ||= NamespaceCache.new(namespace)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ class AttributeMapping < ActiveRecord::Base
2
+ include AttributeMapping::LocalCache
3
+
4
+ def definition
5
+ target_class.attributes[attribute_name]
6
+ end
7
+
8
+ def target_class
9
+ @target_class ||= namespace.constantize
10
+ end
11
+
12
+ def to_option
13
+ [label, value]
14
+ end
15
+ end
@@ -0,0 +1,40 @@
1
+ class AttributeMapping
2
+ module LocalCache
3
+ class MappingCache < Struct.new(:namespace)
4
+ include Traveller::LocalCache
5
+
6
+ def fetch_value
7
+ sql = %{
8
+ SELECT attribute_name, value, label
9
+ FROM attribute_mappings
10
+ WHERE namespace = #{AttributeMapping.connection.quote(namespace)}
11
+ ORDER BY value;
12
+ }.squish!
13
+
14
+ AttributeMapping.connection.select_rows(sql).each_with_object({}) do |a, result|
15
+ name, value, label = a
16
+ result[name] ||= {}
17
+ result[name][value] = label
18
+ end
19
+ end
20
+
21
+ def cache_name
22
+ "attribute_mapping_#{namespace}"
23
+ end
24
+ end
25
+
26
+ extend ActiveSupport::Concern
27
+
28
+ included do
29
+ after_save { self.class.cached_mapping_for(namespace).expire! }
30
+ after_destroy { self.class.cached_mapping_for(namespace).expire! }
31
+ end
32
+
33
+ module ClassMethods
34
+ def cached_mapping_for(namespace)
35
+ @cached_mappings ||= {}
36
+ @cached_mappings[namespace] ||= MappingCache.new(namespace)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'axle_attributes'
5
+ s.version = "1.13.2"
6
+ s.summary = 'Attribute framework for Data Axle'
7
+ s.description = 'Why'
8
+
9
+ s.required_ruby_version = '>= 2.0.0'
10
+ s.required_rubygems_version = '>= 1.8.0'
11
+
12
+ s.author = 'Matthew Higgins'
13
+ s.email = 'developer@matthewhiggins.com'
14
+ s.homepage = 'http://github.com/data-axle/axle_attributes'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+
18
+ s.add_dependency "rails", ">= 4.0"
19
+ s.add_dependency 'elastic_record'
20
+ s.add_dependency 'axle_traveller'
21
+ s.add_dependency 'superstore', '>= 1.0.10'
22
+ end
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/axle_attributes/engine', __FILE__)
6
+
7
+ require 'rails/all'
8
+ require 'rails/engine/commands'
@@ -0,0 +1,16 @@
1
+ class CreateAttributeCustomizations < ActiveRecord::Migration
2
+ def change
3
+ create_table :attribute_customizations do |t|
4
+ t.string :namespace, null: false
5
+ t.string :name, null: false
6
+ t.text :aliases_csv
7
+ t.date :deprecated_on
8
+ t.string :display_name
9
+ t.text :description
10
+ t.string :instructions
11
+ t.text :notes
12
+ t.index [:namespace, :name], unique: true
13
+ t.timestamps
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ class CreateAttributeMappings < ActiveRecord::Migration
2
+ def change
3
+ create_table :attribute_mappings do |t|
4
+ t.string :label
5
+ t.string :value
6
+ t.string :attribute_name, null: false
7
+ t.string :namespace, null: false
8
+ t.string :default # ?
9
+ t.integer :mapped_value # ?
10
+ t.float :fill_rate # ?
11
+ t.string :status # ?
12
+ t.timestamps
13
+
14
+ t.index [:namespace, :attribute_name, :value], name: 'index_attribute_mappings'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ class AddEditableToAttributeCustomizations < ActiveRecord::Migration
2
+ def change
3
+ change_table :attribute_customizations do |t|
4
+ t.boolean :editable, null: false, default: true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_support/dependencies/autoload'
2
+ require 'active_support/concern'
3
+
4
+ require 'active_model'
5
+ require 'elastic_record'
6
+ require 'superstore'
7
+ require 'axle_traveller'
8
+
9
+ require 'axle_attributes/engine'
10
+
11
+ module AxleAttributes
12
+ extend ActiveSupport::Autoload
13
+
14
+ autoload :ChildDefinition
15
+ autoload :Conversions
16
+ autoload :Definition
17
+ autoload :Dumper
18
+ autoload :Format
19
+ autoload :HasAttributes
20
+ autoload :Model
21
+ autoload :NullDefinition
22
+ autoload :ParentDefinition
23
+ autoload :Provided
24
+ autoload :Regex
25
+ autoload :Segmented
26
+ autoload :Serializations
27
+ autoload :SerializedChild
28
+ autoload :Validations
29
+ autoload :Versioned
30
+ end
@@ -0,0 +1,42 @@
1
+ module AxleAttributes
2
+ class ChildDefinition < ::AxleAttributes::Definition
3
+ attr_accessor :nested_path
4
+
5
+ setup do
6
+ setup_storage! unless name == 'id'
7
+ setup_versioning!
8
+ end
9
+
10
+ def display_name
11
+ human = model.model_name.human
12
+ human = human.pluralize if nested_path
13
+ "#{human}: #{super}"
14
+ end
15
+
16
+ def canonical_name
17
+ @canonical_name ||= "#{model.model_name.send(nested_path ? :plural : :singular)}.#{name}"
18
+ end
19
+
20
+ private
21
+
22
+ def setup_storage!
23
+ if type
24
+ storage_options = case type
25
+ when :text
26
+ {type: :string}
27
+ else
28
+ options.slice(:type, :default)
29
+ end
30
+
31
+ model.attribute(name, storage_options)
32
+ end
33
+ end
34
+
35
+ def setup_versioning!
36
+ if versioned?
37
+ model.add_versioned_attribute name
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,36 @@
1
+ module AxleAttributes
2
+ module Conversions
3
+ def self.included(base)
4
+ if base.is_a? Class
5
+ base.class_eval do
6
+ cattr_accessor :target_class
7
+ def self.use_target_class(target_class)
8
+ self.target_class = target_class
9
+ end
10
+ end
11
+ else
12
+ base.class_eval do
13
+ mattr_accessor :target_class
14
+ def self.use_target_class(target_class)
15
+ self.target_class = target_class
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ class ConversionError < RuntimeError; end
22
+
23
+ module_function
24
+
25
+ def to_definition(*args)
26
+ case args.first
27
+ when AxleAttributes::Definition
28
+ args.first
29
+ when String
30
+ target_class.attributes[args.first] || AxleAttributes::NullDefinition.new(target_class, args.first)
31
+ else
32
+ raise ConversionError.new "Can't convert #{args}.inspect to Field"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,118 @@
1
+ require 'axle_attributes/definition/callbacks'
2
+ require 'axle_attributes/definition/customization'
3
+ require 'axle_attributes/definition/formatted'
4
+ require 'axle_attributes/definition/indexed'
5
+ require 'axle_attributes/definition/mappings'
6
+
7
+ module AxleAttributes
8
+ class Definition
9
+ include AxleAttributes::Definition::Callbacks
10
+
11
+ include AxleAttributes::Definition::Indexed
12
+ include AxleAttributes::Definition::Mappings
13
+ include AxleAttributes::Definition::Formatted
14
+ include AxleAttributes::Definition::Customization
15
+
16
+ attr_accessor :model, :name, :options
17
+ delegate :description, to: :customization, allow_nil: true
18
+
19
+ def initialize(model, name, options = {})
20
+ @model = model
21
+ @name = name.to_s
22
+ @options = options
23
+ end
24
+
25
+ class << self
26
+ def reset_caches
27
+ cached_customizations.clear
28
+ cached_attribute_mappings.clear
29
+ end
30
+ end
31
+
32
+ def setup!
33
+ run_callbacks :setup
34
+ end
35
+
36
+ def canonical_name
37
+ name
38
+ end
39
+
40
+ FILTER_CONTROL_DEFAULTS = {
41
+ float: 'range',
42
+ integer: 'range',
43
+ string: 'text',
44
+ text: 'text',
45
+ boolean: 'radio',
46
+ time: 'daterange'
47
+ }
48
+ def filter_control
49
+ if mapping_model
50
+ mapping_model.respond_to?(:code_hierarchy_lengths) ? 'hierarchy' : 'combo'
51
+ elsif mappings.any?
52
+ 'checkbox'
53
+ else
54
+ FILTER_CONTROL_DEFAULTS.fetch(type, 'text')
55
+ end
56
+ end
57
+
58
+ EDIT_CONTROL_DEFAULTS = {
59
+ float: 'text',
60
+ integer: 'text',
61
+ text: 'textarea',
62
+ string: 'text',
63
+ time: 'filter',
64
+ boolean: 'combo',
65
+ }
66
+ def edit_control
67
+ if mappings.any?
68
+ 'combo'
69
+ else
70
+ EDIT_CONTROL_DEFAULTS[type]
71
+ end
72
+ end
73
+
74
+ def aliases
75
+ result = [name, display_name, options[:mmdb_name], customization.try(:aliases)]
76
+ result.flatten!
77
+ result.compact!
78
+ result
79
+ end
80
+
81
+ def to_param
82
+ name
83
+ end
84
+
85
+ def namespace
86
+ model.name
87
+ end
88
+
89
+ def type
90
+ options[:type]
91
+ end
92
+
93
+ def format
94
+ options[:format]
95
+ end
96
+
97
+ def readonly?
98
+ !editable?
99
+ end
100
+
101
+ def editable?
102
+ editable_customization && !deprecated? && options.fetch(:editable, true)
103
+ end
104
+
105
+ def indexed?
106
+ options[:index]
107
+ end
108
+
109
+ def versioned?
110
+ options[:version]
111
+ end
112
+
113
+ def default
114
+ options[:default]
115
+ end
116
+
117
+ end
118
+ end