omg-attrs 0.1.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/README.md +45 -0
- data/attrs.gemspec +26 -0
- data/lib/attrs.rb +60 -0
- data/spec/attrs_spec.rb +43 -0
- data/spec/spec_helper.rb +15 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f3eaed4c8a55dca3f9d6e4c6ecd00781116986cc1c81d1105960225bbfb74a85
|
4
|
+
data.tar.gz: 65c6269712e3e992694866d0c95a96b8d27b3542e78807c7a842cc1bcc4fbc25
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4c5c5c1d6c2b3fa0604cb1c930f87b3953b62c3679066deca0818e132187cc37579037886f8ff0d1e0daaf4c426d7a0c68de0da2997b4380b41cc7d209754fa2
|
7
|
+
data.tar.gz: 04c77582e0256724d3ed1dfa090dd398a3b5da7e5c5e0b450b94bf388532ca076fa7f3a03dbf51ddf0e04201e81b9268284a88e6970105d6785ccff4a61b2ea5
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Attrs
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
### Testing locally
|
6
|
+
```sh
|
7
|
+
# Build gem
|
8
|
+
gem build attrs.gemspec
|
9
|
+
|
10
|
+
# Install gem
|
11
|
+
gem i -l /path/to/this/folder/omg-attrs-0.1.0.gem
|
12
|
+
```
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
dad_hash = {
|
18
|
+
age: 35,
|
19
|
+
hair_color: 'brown',
|
20
|
+
children: [
|
21
|
+
{ age: 7, hair_color: 'blonde' },
|
22
|
+
{ age: 3, hair_color: 'brown' }
|
23
|
+
],
|
24
|
+
wife: { age: 35, hair_color: 'brown' }
|
25
|
+
}
|
26
|
+
|
27
|
+
dad_hash.attrs(:age) # => 35
|
28
|
+
dad_hash.attrs(wife: :age, children: :hair_color) # =>
|
29
|
+
# {
|
30
|
+
# wife: 35,
|
31
|
+
# children: [
|
32
|
+
# { hair_color: 'blonde' },
|
33
|
+
# { hair_color: 'brown' },
|
34
|
+
# ],
|
35
|
+
# }
|
36
|
+
```
|
37
|
+
|
38
|
+
## Running tests
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
rspec
|
42
|
+
|
43
|
+
# or
|
44
|
+
bundle exec rspec
|
45
|
+
```
|
data/attrs.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'omg-attrs'
|
5
|
+
spec.version = '0.1.0'
|
6
|
+
spec.authors = ['Matthew Greenfield']
|
7
|
+
spec.email = ['mattgreenfield1@gmail.com']
|
8
|
+
|
9
|
+
spec.summary = 'Allows all objects to call `.attrs` which acts as a recursive `.slice` method'
|
10
|
+
spec.description = 'Makes it easy to slice and dice objects and collections of objects'
|
11
|
+
|
12
|
+
spec.homepage = 'https://github.com/omgreenfield/omg-util/tree/main/attrs'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.required_ruby_version = '>= 2.7.0'
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
18
|
+
|
19
|
+
spec.files = Dir.chdir(__dir__) do
|
20
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
21
|
+
(File.expand_path(f) == __FILE__) ||
|
22
|
+
f.start_with?(*%w[spec/.git .github Gemfile])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
spec.require_paths = ['lib']
|
26
|
+
end
|
data/lib/attrs.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attrs
|
4
|
+
def self.included(base)
|
5
|
+
base.include(InstanceMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
def attrs(*attrs)
|
10
|
+
return map { |i| i.attrs(*attrs) } if is_list?(self)
|
11
|
+
|
12
|
+
base_attrs, nested_attrs = attrs.partition { |attr| attr.is_a?(Symbol) }
|
13
|
+
nested_attrs.map! do |attr|
|
14
|
+
if attr.is_a?(Hash)
|
15
|
+
nested_attrs(attr)
|
16
|
+
elsif attr.is_a?(Array) && attr.size == 2 && attr.first.is_a?(Symbol)
|
17
|
+
nested_attrs([attr].to_h)
|
18
|
+
elsif attr.is_a?(Array)
|
19
|
+
attr.map { |a| a.attrs(a) }
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Invalid attribute: #{attr}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
base_attrs = base_attrs.to_h { |attr| [attr, get(attr)] }
|
26
|
+
nested_attrs.reduce(base_attrs, :merge)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def nested_attrs(attr)
|
32
|
+
attr.to_h do |key, value|
|
33
|
+
records = get(key)
|
34
|
+
|
35
|
+
values = is_list?(records) ?
|
36
|
+
records.map { |record| record.attrs(*value) } :
|
37
|
+
records.attrs(*value)
|
38
|
+
|
39
|
+
[key, values]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def get(key)
|
44
|
+
if respond_to?(key)
|
45
|
+
send(key)
|
46
|
+
elsif is_a?(Hash)
|
47
|
+
self[key]
|
48
|
+
else
|
49
|
+
# Denoting that the object does not respond to that key
|
50
|
+
NilClass
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def is_list?(object)
|
55
|
+
object.is_a?(Enumerable) && !object.is_a?(Hash)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Object.include Attrs
|
data/spec/attrs_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
RSpec.describe Attrs do
|
6
|
+
it 'allows recursive slice-like attribute fetching' do
|
7
|
+
dad_hash = {
|
8
|
+
age: 35,
|
9
|
+
hair_color: 'brown',
|
10
|
+
children: [
|
11
|
+
{ age: 7, hair_color: 'blonde' },
|
12
|
+
{ age: 3, hair_color: 'brown' }
|
13
|
+
],
|
14
|
+
wife: { age: 35, hair_color: 'brown' }
|
15
|
+
}
|
16
|
+
|
17
|
+
expect(dad_hash.attrs(:age, wife: %i[hair_color age], children: %i[hair_color age])).to eq(
|
18
|
+
{
|
19
|
+
age: 35,
|
20
|
+
wife: { hair_color: 'brown', age: 35 },
|
21
|
+
children: [
|
22
|
+
{ hair_color: 'blonde', age: 7 },
|
23
|
+
{ hair_color: 'brown', age: 3 },
|
24
|
+
],
|
25
|
+
}
|
26
|
+
)
|
27
|
+
|
28
|
+
dad_object = OpenStruct.new(dad_hash)
|
29
|
+
expect(dad_object.attrs(:age, wife: %i[hair_color age], children: %i[hair_color age])).to eq(
|
30
|
+
{
|
31
|
+
age: 35,
|
32
|
+
wife: { hair_color: 'brown', age: 35 },
|
33
|
+
children: [
|
34
|
+
{ hair_color: 'blonde', age: 7 },
|
35
|
+
{ hair_color: 'brown', age: 3 },
|
36
|
+
],
|
37
|
+
}
|
38
|
+
)
|
39
|
+
|
40
|
+
children_array = dad_object.children
|
41
|
+
expect(children_array.attrs(:hair_color, :age)).to eq([{ hair_color: 'blonde', age: 7 }, { hair_color: 'brown', age: 3 }])
|
42
|
+
end
|
43
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "attrs"
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
# Enable flags like --only-failures and --next-failure
|
7
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
8
|
+
|
9
|
+
# Disable RSpec exposing methods globally on `Module` and `main`
|
10
|
+
config.disable_monkey_patching!
|
11
|
+
|
12
|
+
config.expect_with :rspec do |c|
|
13
|
+
c.syntax = :expect
|
14
|
+
end
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omg-attrs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthew Greenfield
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-04-30 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Makes it easy to slice and dice objects and collections of objects
|
14
|
+
email:
|
15
|
+
- mattgreenfield1@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".rspec"
|
21
|
+
- ".rubocop.yml"
|
22
|
+
- README.md
|
23
|
+
- attrs.gemspec
|
24
|
+
- lib/attrs.rb
|
25
|
+
- spec/attrs_spec.rb
|
26
|
+
- spec/spec_helper.rb
|
27
|
+
homepage: https://github.com/omgreenfield/omg-util/tree/main/attrs
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata:
|
31
|
+
homepage_uri: https://github.com/omgreenfield/omg-util/tree/main/attrs
|
32
|
+
rubygems_mfa_required: 'true'
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 2.7.0
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubygems_version: 3.5.9
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: Allows all objects to call `.attrs` which acts as a recursive `.slice` method
|
52
|
+
test_files: []
|