omg-attrs 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.7.8
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: single_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: single_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
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
@@ -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
@@ -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: []