property_string 0.0.1

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: 1599cc1dcb3a805c49f5d128df2d3c0a2a1d6de8d8f1348dba0e75a39d28827a
4
+ data.tar.gz: 4d62dcd17afbb2463114cb26a676b56ac25ea3f8da4adfdda0fadcdc5b7d48fb
5
+ SHA512:
6
+ metadata.gz: 06d7eb0788c96fcd4a63d06f423b17568c1237f7070ffa19834cf4cde5036824d01da0cf5205dde497fb3e7f4bb5c75bd79bb5a92eb1cfadecbe69db32de82da
7
+ data.tar.gz: ab9f57a4adc63d312fc1acd376617e35ff170732174277ce85624a8563757202d600670a684cffe35d71e785500b662b9230135bfd71c4e89c0ab194080fa646
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in property_string.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Skye Shaw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # PropertyString
2
+
3
+ ![PropertyString CI Status](https://github.com/sshaw/property_string/workflows/CI/badge.svg "PropertyString CI Status")
4
+
5
+ Use Java-style property notation to execute method call chains on an object.
6
+
7
+ ## Installation
8
+
9
+ Install the gem and add to the application's Gemfile by executing:
10
+
11
+ bundle add property_string
12
+
13
+ If bundler is not being used to manage dependencies, install the gem by executing:
14
+
15
+ gem install property_string
16
+
17
+ ## Usage
18
+
19
+ ```rb
20
+ # Object call chain
21
+ product.company.name # bar
22
+
23
+ ps = PropertyString.new(product)
24
+ ps["company.name"] # bar
25
+
26
+ # Object call chain with Array-like object
27
+ user.posts[0].replied_to.name # sshaw
28
+
29
+ ps = PropertyString.new(user)
30
+ ps["posts.0.replied_to.name"] # sshaw
31
+
32
+ # Method does not exist
33
+ ps = PropertyString.new(product)
34
+ ps["company.does_not_exist!"] # NoMethodError
35
+
36
+ # Can work with a Hash
37
+ h.dig(:some, "nested", :hash) # foo
38
+
39
+ ph = PropertyString(h)
40
+ ph["some.nested.hash"]
41
+
42
+ # Or an Array
43
+ a[0][0][0]
44
+
45
+ ph = PropertyString(a)
46
+ ph["0.0.0"]
47
+
48
+ # Ignore MethodMissing errors for unknown properties
49
+ ps = PropertyString.new(product, :raise_if_method_missing => false)
50
+ ps["company.does_not_exist!"] # nil
51
+
52
+ # Fetching
53
+ ps.fetch("posts.9999", "your default") # shaw
54
+ ps.fetch("posts.9999") { |key| "some_default_for_#{key}" }
55
+ ```
56
+
57
+ ## See Also
58
+
59
+ - [PropertyHash](https://github.com/sshaw/property_hash) - Access a nested Ruby Hash using Java-style properties as keys.
60
+
61
+ ## Contributing
62
+
63
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sshaw/property_string.
64
+
65
+ ## License
66
+
67
+ 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,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PropertyString
4
+ VERSION = "0.0.1"
5
+ KEY_NOT_FOUND = "__#{object_id}-not-found-placeholder-#{object_id}__"
6
+
7
+ def initialize(object, options = nil)
8
+ @object = object
9
+
10
+ @options = (options || {}).dup
11
+ @options[:raise_if_method_missing] = true unless @options.include?(:raise_if_method_missing)
12
+ end
13
+
14
+ def [](property)
15
+ value = fetch_property_chain(property)
16
+ value = nil if value == KEY_NOT_FOUND
17
+ value
18
+ end
19
+
20
+ def fetch(property, *default, &block)
21
+ fetch_default = -> do
22
+ raise KeyError, "property #{property} not found" unless default.any? || block_given?
23
+ block_given? ? block[property] : default[0]
24
+ end
25
+
26
+ value = nil
27
+
28
+ begin
29
+ value = fetch_property_chain(property)
30
+ return value unless value == KEY_NOT_FOUND
31
+ rescue NoMethodError => e
32
+ warn e if ENV["DEBUG"]
33
+ return fetch_default[]
34
+ end
35
+
36
+ fetch_default[]
37
+ end
38
+
39
+ def inspect
40
+ @object.inspect
41
+ end
42
+
43
+ private
44
+
45
+ def fetch_property_chain(property)
46
+ value = @object
47
+
48
+ chain = String(property).split(".")
49
+ chain.each do |prop|
50
+ value = prop.match?(/\A\d+\z/) ? find_index_value(value, prop) : find_non_index_value(value, prop)
51
+ break if value.nil? || value == KEY_NOT_FOUND
52
+ end
53
+
54
+ value
55
+ end
56
+
57
+ def find_non_index_value(value, prop)
58
+ if value.is_a?(Hash)
59
+ value = find_hash_value(value, prop)
60
+ value == KEY_NOT_FOUND ? nil : value
61
+ elsif @options[:raise_if_method_missing]
62
+ value.public_send(prop)
63
+ elsif value.respond_to?(prop)
64
+ value.public_send(prop)
65
+ end
66
+ end
67
+
68
+ def find_index_value(value, prop)
69
+ unless value.respond_to?(:[])
70
+ raise TypeError, "Cannot access index #{prop} on #{value.class}"
71
+ end
72
+
73
+ if !value.is_a?(Hash)
74
+ int_prop = prop.to_i
75
+ av = value[int_prop]
76
+ # Check if index even exists to determine if this should be a KEY_NOT_FOUND
77
+ return av if !av.nil? || !value.respond_to?(:size) || int_prop < value.size
78
+ else
79
+ hv = find_hash_value(value, prop)
80
+ return hv if hv != KEY_NOT_FOUND
81
+
82
+ int_index = prop.to_i
83
+ return value[int_index] if value.include?(int_index)
84
+ end
85
+
86
+ KEY_NOT_FOUND
87
+ end
88
+
89
+ def find_hash_value(hash, prop)
90
+ return hash[prop] if hash.include?(prop)
91
+
92
+ sym_prop = prop.to_sym
93
+ return hash[sym_prop] if hash.include?(sym_prop)
94
+
95
+ KEY_NOT_FOUND
96
+ end
97
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/property_string"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "property_string"
7
+ spec.version = PropertyString::VERSION
8
+ spec.authors = ["sshaw"]
9
+ spec.email = ["skye.shaw@gmail.com"]
10
+
11
+ spec.summary = "Use Java-style property notation to execute method call chains on an object."
12
+ spec.homepage = "https://github.com/sshaw/property_string"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 2"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
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(__dir__) do
23
+ `git ls-files -z`.split("\x0").reject do |f|
24
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
25
+ end
26
+ end
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_development_dependency "bundler"
32
+ spec.add_development_dependency "rake", "~> 13.0"
33
+ spec.add_development_dependency "rspec", "~> 3.0"
34
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: property_string
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - sshaw
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description:
56
+ email:
57
+ - skye.shaw@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".rspec"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/property_string.rb
68
+ - property_string.gemspec
69
+ homepage: https://github.com/sshaw/property_string
70
+ licenses:
71
+ - MIT
72
+ metadata:
73
+ homepage_uri: https://github.com/sshaw/property_string
74
+ source_code_uri: https://github.com/sshaw/property_string
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '2'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubygems_version: 3.1.4
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Use Java-style property notation to execute method call chains on an object.
94
+ test_files: []