column_namespace 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 851cc54004fb49af7ab29acf1b0adb5d887e54246397058aed37de7f3761b5f7
4
+ data.tar.gz: 18f116ac4a131c58a27aeea0baf575bc7e5c392ac1e4b667bc614b955d538bcb
5
+ SHA512:
6
+ metadata.gz: 19e4d8ef5552f60155fe65ec73f0a704aa3e2d18b9311c06ecddce80fca924f6ae2c1a8e58f06d2b169d804264a759893e5ed80c03213d2adf3bac4f93258782
7
+ data.tar.gz: a6e06fd4d6a22db02df72eb27c5e6596888d0cfdf46b95011200bc5f34b91628177e59b147c3778671b537937a52d6fe87448248a6fe9ee8d4273d182c0252b2
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,33 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.3
7
+ - 2.4
8
+ - 2.5
9
+ - 2.6
10
+ - 2.7
11
+
12
+ before_install:
13
+ - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
14
+ - gem install bundler -v '< 2'
15
+
16
+ gemfile:
17
+ - gemfiles/4.2.gemfile
18
+ - gemfiles/5.0.gemfile
19
+ - gemfiles/5.1.gemfile
20
+ - gemfiles/5.2.gemfile
21
+ - gemfiles/6.0.gemfile
22
+
23
+ matrix:
24
+ exclude:
25
+ - rvm: 2.3
26
+ gemfile: gemfiles/6.0.gemfile
27
+ - rvm: 2.4
28
+ gemfile: gemfiles/6.0.gemfile
29
+ - rvm: 2.7
30
+ gemfile: gemfiles/4.2.gemfile
31
+
32
+ notifications:
33
+ email: false
data/Appraisals ADDED
@@ -0,0 +1,24 @@
1
+ appraise "4.2" do
2
+ gem "activerecord", "~> 4.2.11"
3
+ gem "sqlite3", "~> 1.3.6"
4
+ end
5
+
6
+ appraise "5.0" do
7
+ gem "activerecord", "~> 5.0.7"
8
+ gem "sqlite3", "~> 1.3.6"
9
+ end
10
+
11
+ appraise "5.1" do
12
+ gem "activerecord", "~> 5.1.7"
13
+ gem "sqlite3"
14
+ end
15
+
16
+ appraise "5.2" do
17
+ gem "activerecord", "~> 5.2.4"
18
+ gem "sqlite3"
19
+ end
20
+
21
+ appraise "6.0" do
22
+ gem "activerecord", "~> 6.0.2"
23
+ gem "sqlite3"
24
+ end
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in column_namespace.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # Column Namespace
2
+
3
+ [![Build Status](https://travis-ci.org/sshaw/column_namespace.svg?branch=master)](https://travis-ci.org/sshaw/column_namespace)
4
+
5
+ Group columns on your Active Record model under a "namespace method".
6
+
7
+ ## Usage
8
+
9
+ Given the following database table (note the columns beginning with `"external_"`):
10
+ ```sql
11
+ create table products (
12
+ id int unsigned,
13
+ name varchar(255),
14
+ external_product_id bigint unsigned,
15
+ external_variant_id bigint unsigned,
16
+ external_metafield_id bigint unsigned
17
+ )
18
+ ```
19
+
20
+ Add the following to its model:
21
+ ```ruby
22
+ class Product < ApplicationRecord
23
+ extend ColumnNamespace
24
+ column_namespace "external_"
25
+ end
26
+ ```
27
+
28
+ Now you can do:
29
+ ```ruby
30
+ product = Product.new(:external => { :product_id => 123, :variant_id => 999 })
31
+
32
+ p product.external.product_id # 123
33
+ p product.external.variant_id # 999
34
+
35
+ product.save!
36
+
37
+ p product[:external_variant_id] # 999
38
+
39
+ product.external.variant_id = 21341510
40
+ product.save!
41
+
42
+ product[:external_variant_id] # 21341510
43
+
44
+ product = Product.last
45
+ p product.external.to_h # { :product_id => 1, :metafield_id => nil, ... }
46
+ ```
47
+
48
+ Alternatively you can specify the namespace method and its columns:
49
+ ```ruby
50
+ class Product < ApplicationRecord
51
+ extend ColumnNamespace
52
+ column_namespace :some_method => %w[name external_product_id]
53
+ end
54
+ ```
55
+
56
+ This gives you:
57
+ ```ruby
58
+ product = Product.new(:some_method => { :name => "sshaw", :external_product_id => 99 })
59
+ product.some_method.name = nil
60
+ product.some_method.external_product_id = 1_000_00
61
+
62
+ # etc... same stuff as before
63
+ ```
64
+
65
+
66
+ ### But Isn't This What `composed_of` Does‽
67
+
68
+ Yes, but, no!
69
+
70
+ `composed_of` forces you to create and explicitly use a "value object". In some cases (like in the above examples)
71
+ this class is artificial. It doesn't exist in your domain –nor should it!
72
+
73
+ Using the above examples with `composed_of` do not work. Instead of:
74
+ ```ruby
75
+ product = Product.last
76
+ product.external.product_id = 510
77
+ product.save! # does not save 510
78
+ ```
79
+
80
+ You'd have to write:
81
+ ```ruby
82
+ product = Product.last
83
+ product.external = External.new(:product_id => 510)
84
+ product.save!
85
+ ```
86
+
87
+ The same applies for validation:
88
+ ```ruby
89
+ # In Product:
90
+ # validates :external_product_id, :numericality => { :greater_than => -1 }
91
+ product = Product.last
92
+ product.external.product_id = -1
93
+ product.valid? # true
94
+ ```
95
+
96
+ You'd have to assign an instance of `External` to `product.external` for this to work.
97
+
98
+ ## Installation
99
+
100
+ Add this line to your application's Gemfile:
101
+
102
+ ```ruby
103
+ gem "column_namespace"
104
+ ```
105
+
106
+ Or:
107
+
108
+ ```
109
+ gem install column_namespace
110
+ ```
111
+
112
+ ## Author
113
+
114
+ Skye Shaw [skye.shaw AT gmail.com]
115
+
116
+ ## License
117
+
118
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,36 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "column_namespace/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "column_namespace"
8
+ spec.version = ColumnNamespace::VERSION
9
+ spec.authors = ["Skye Shaw"]
10
+ spec.email = ["skye.shaw@gmail.com"]
11
+
12
+ spec.summary = %q{Group columns on your Active Record model under a "namespace method".}
13
+ spec.homepage = "https://github.com/sshaw/column_namespace"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["bug_tracker_uri"] = "https://github.com/sshaw/column_namespace/issues"
18
+ spec.metadata["changelog_uri"] = "https://github.com/sshaw/column_namespace/blob/master/Changes"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_dependency "class2", "~> 0.5.2"
30
+ spec.add_dependency "activerecord", ">= 4.2", "< 7"
31
+
32
+ spec.add_development_dependency "appraisal"
33
+ spec.add_development_dependency "bundler"
34
+ spec.add_development_dependency "rake", ">= 12.3.3"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.2.11"
6
+ gem "sqlite3", "~> 1.3.6"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.0.7"
6
+ gem "sqlite3", "~> 1.3.6"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.1.7"
6
+ gem "sqlite3"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.2.4"
6
+ gem "sqlite3"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 6.0.2"
6
+ gem "sqlite3"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "column_namespace/version"
4
+ require "class2"
5
+
6
+ module ColumnNamespace
7
+ def column_namespace(options)
8
+ if options.is_a?(Hash)
9
+ namespace_via_list(options)
10
+ return
11
+ end
12
+
13
+ Array.wrap(options).each { |prefix| namespace_via_prefix(prefix) }
14
+ end
15
+
16
+ private
17
+
18
+ def namespace_via_list(config)
19
+ config.each do |namespace, columns|
20
+ unknown = columns.map(&:to_s) - column_names
21
+ raise "unknown column(s): #{unknown.to_sentence}" unless unknown.empty?
22
+
23
+ klass = namespace.to_s.classify
24
+ class2 self, klass => columns
25
+
26
+ class_eval(<<-CODE)
27
+ def #{namespace}
28
+ @__#{namespace} ||= #{klass}.new(attributes.slice(*#{columns}))
29
+ end
30
+
31
+ def #{namespace}=(instance_or_attributes)
32
+ @__#{namespace} = instance_or_attributes.is_a?(Hash) ? #{klass}.new(instance_or_attributes) : instance_or_attributes
33
+ end
34
+
35
+ before_validation do
36
+ #{namespace}.to_h.each do |key, value|
37
+ self[key] = value
38
+ end
39
+ end
40
+ CODE
41
+ end
42
+ end
43
+
44
+ def namespace_via_prefix(prefix)
45
+ columns = column_names.select { |name| name.starts_with?(prefix) }
46
+ raise "No attributes found with prefix #{prefix}" unless columns.any?
47
+
48
+ method = prefix.sub(/[^[:alnum]]*\z/i, "")
49
+ klass = method.classify
50
+ prefix_regex = /\A#{Regexp.quote(prefix)}[^[:alnum:]]*/
51
+
52
+ class2 self, klass => columns.map { |name| name.sub(prefix_regex, "") }
53
+
54
+ class_eval(<<-CODE)
55
+ def #{method}
56
+ @__#{method} ||= #{klass}.new(attributes.slice(*#{columns}).transform_keys! { |k| k.sub(/#{prefix_regex}/, "") })
57
+ end
58
+
59
+ def #{method}=(instance_or_attributes)
60
+ @__#{method} = instance_or_attributes.is_a?(Hash) ? #{klass}.new(instance_or_attributes) : instance_or_attributes
61
+ end
62
+
63
+ before_validation do
64
+ #{method}.to_h.each do |key, value|
65
+ self["#{prefix}\#{key}"] = value
66
+ end
67
+ end
68
+ CODE
69
+ end
70
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ColumnNamespace
4
+ VERSION = "0.0.1"
5
+ end
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: column_namespace
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Skye Shaw
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-05-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: class2
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '4.2'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '7'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '4.2'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '7'
47
+ - !ruby/object:Gem::Dependency
48
+ name: appraisal
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 12.3.3
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 12.3.3
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.0'
103
+ description:
104
+ email:
105
+ - skye.shaw@gmail.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - ".gitignore"
111
+ - ".rspec"
112
+ - ".travis.yml"
113
+ - Appraisals
114
+ - Gemfile
115
+ - README.md
116
+ - Rakefile
117
+ - column_namespace.gemspec
118
+ - gemfiles/4.2.gemfile
119
+ - gemfiles/5.0.gemfile
120
+ - gemfiles/5.1.gemfile
121
+ - gemfiles/5.2.gemfile
122
+ - gemfiles/6.0.gemfile
123
+ - lib/column_namespace.rb
124
+ - lib/column_namespace/version.rb
125
+ homepage: https://github.com/sshaw/column_namespace
126
+ licenses:
127
+ - MIT
128
+ metadata:
129
+ homepage_uri: https://github.com/sshaw/column_namespace
130
+ bug_tracker_uri: https://github.com/sshaw/column_namespace/issues
131
+ changelog_uri: https://github.com/sshaw/column_namespace/blob/master/Changes
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubyforge_project:
148
+ rubygems_version: 2.7.6
149
+ signing_key:
150
+ specification_version: 4
151
+ summary: Group columns on your Active Record model under a "namespace method".
152
+ test_files: []