q_hash 0.1.2 → 0.2.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 +4 -4
- data/.github/workflows/main.yml +6 -2
- data/Gemfile +7 -1
- data/Gemfile.lock +45 -9
- data/README.md +27 -0
- data/Rakefile +4 -1
- data/Steepfile +7 -0
- data/bin/release +16 -0
- data/lib/q_hash.rb +15 -22
- data/sig/q_hash.rbs +18 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b5ef11c5099019641fbe1de713e1be087f9775f58571cb87a1554ad0155956e
|
4
|
+
data.tar.gz: 4ddad57fda9b5b8ffdf078cf432ed1b5ebf960928be1058341a54ae567ad43f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edc0f7958090f8cb5720385622759bdc840c88d348c4c9fc519f4496f264d2dc8b15ca2fe952f7da9441a21bf1ba30eec667d53554a9bd9d5170b917ff232e81
|
7
|
+
data.tar.gz: 13fb94e70543d0a5dfe64add5cefdab276d906df332e48386a78933dabd1dd04f52f1960118e5d0da1a7e9e228ef82c7387d437248de56a2db04fd13932aa674
|
data/.github/workflows/main.yml
CHANGED
@@ -16,5 +16,9 @@ jobs:
|
|
16
16
|
with:
|
17
17
|
ruby-version: ${{ matrix.ruby }}
|
18
18
|
bundler-cache: true
|
19
|
-
- name:
|
20
|
-
run: bundle exec rake
|
19
|
+
- name: Linter
|
20
|
+
run: bundle exec rake standard
|
21
|
+
- name: Test
|
22
|
+
run: bundle exec rake spec
|
23
|
+
- name: Type Check
|
24
|
+
run: bundle exec rake steep
|
data/Gemfile
CHANGED
@@ -5,10 +5,16 @@ source "https://rubygems.org"
|
|
5
5
|
# Specify your gem's dependencies in q_hash.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
+
gem "activesupport", "< 7.0"
|
9
|
+
|
8
10
|
gem "rake", "~> 13.0"
|
9
11
|
|
12
|
+
gem "rbs"
|
13
|
+
|
10
14
|
gem "rspec", "~> 3.0"
|
11
15
|
|
16
|
+
gem "simplecov"
|
17
|
+
|
12
18
|
gem "standard"
|
13
19
|
|
14
|
-
gem "
|
20
|
+
gem "steep"
|
data/Gemfile.lock
CHANGED
@@ -1,20 +1,39 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
q_hash (0.
|
4
|
+
q_hash (0.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
activesupport (6.1.6)
|
10
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
+
i18n (>= 1.6, < 2)
|
12
|
+
minitest (>= 5.1)
|
13
|
+
tzinfo (~> 2.0)
|
14
|
+
zeitwerk (~> 2.3)
|
9
15
|
ast (2.4.2)
|
16
|
+
concurrent-ruby (1.1.10)
|
10
17
|
diff-lcs (1.5.0)
|
11
18
|
docile (1.4.0)
|
19
|
+
ffi (1.15.5)
|
20
|
+
i18n (1.10.0)
|
21
|
+
concurrent-ruby (~> 1.0)
|
22
|
+
language_server-protocol (3.16.0.3)
|
23
|
+
listen (3.7.1)
|
24
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
25
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
26
|
+
minitest (5.15.0)
|
12
27
|
parallel (1.22.1)
|
13
|
-
parser (3.1.
|
28
|
+
parser (3.1.2.0)
|
14
29
|
ast (~> 2.4.1)
|
15
30
|
rainbow (3.1.1)
|
16
31
|
rake (13.0.6)
|
17
|
-
|
32
|
+
rb-fsevent (0.11.1)
|
33
|
+
rb-inotify (0.10.1)
|
34
|
+
ffi (~> 1.0)
|
35
|
+
rbs (2.5.0)
|
36
|
+
regexp_parser (2.4.0)
|
18
37
|
rexml (3.2.5)
|
19
38
|
rspec (3.11.0)
|
20
39
|
rspec-core (~> 3.11.0)
|
@@ -29,16 +48,16 @@ GEM
|
|
29
48
|
diff-lcs (>= 1.2.0, < 2.0)
|
30
49
|
rspec-support (~> 3.11.0)
|
31
50
|
rspec-support (3.11.0)
|
32
|
-
rubocop (1.
|
51
|
+
rubocop (1.29.1)
|
33
52
|
parallel (~> 1.10)
|
34
53
|
parser (>= 3.1.0.0)
|
35
54
|
rainbow (>= 2.2.2, < 4.0)
|
36
55
|
regexp_parser (>= 1.8, < 3.0)
|
37
|
-
rexml
|
38
|
-
rubocop-ast (>= 1.
|
56
|
+
rexml (>= 3.2.5, < 4.0)
|
57
|
+
rubocop-ast (>= 1.17.0, < 2.0)
|
39
58
|
ruby-progressbar (~> 1.7)
|
40
59
|
unicode-display_width (>= 1.4.0, < 3.0)
|
41
|
-
rubocop-ast (1.
|
60
|
+
rubocop-ast (1.18.0)
|
42
61
|
parser (>= 3.1.1.0)
|
43
62
|
rubocop-performance (1.13.3)
|
44
63
|
rubocop (>= 1.7.0, < 2.0)
|
@@ -50,21 +69,38 @@ GEM
|
|
50
69
|
simplecov_json_formatter (~> 0.1)
|
51
70
|
simplecov-html (0.12.3)
|
52
71
|
simplecov_json_formatter (0.1.4)
|
53
|
-
standard (1.
|
54
|
-
rubocop (= 1.
|
72
|
+
standard (1.12.1)
|
73
|
+
rubocop (= 1.29.1)
|
55
74
|
rubocop-performance (= 1.13.3)
|
75
|
+
steep (1.0.0)
|
76
|
+
activesupport (>= 5.1)
|
77
|
+
language_server-protocol (>= 3.15, < 4.0)
|
78
|
+
listen (~> 3.0)
|
79
|
+
parallel (>= 1.0.0)
|
80
|
+
parser (>= 3.0)
|
81
|
+
rainbow (>= 2.2.2, < 4.0)
|
82
|
+
rbs (>= 2.3.2)
|
83
|
+
terminal-table (>= 2, < 4)
|
84
|
+
terminal-table (3.0.2)
|
85
|
+
unicode-display_width (>= 1.1.1, < 3)
|
86
|
+
tzinfo (2.0.4)
|
87
|
+
concurrent-ruby (~> 1.0)
|
56
88
|
unicode-display_width (2.1.0)
|
89
|
+
zeitwerk (2.5.4)
|
57
90
|
|
58
91
|
PLATFORMS
|
59
92
|
x86_64-darwin-20
|
60
93
|
x86_64-linux
|
61
94
|
|
62
95
|
DEPENDENCIES
|
96
|
+
activesupport (< 7.0)
|
63
97
|
q_hash!
|
64
98
|
rake (~> 13.0)
|
99
|
+
rbs
|
65
100
|
rspec (~> 3.0)
|
66
101
|
simplecov
|
67
102
|
standard
|
103
|
+
steep
|
68
104
|
|
69
105
|
BUNDLED WITH
|
70
106
|
2.3.11
|
data/README.md
CHANGED
@@ -1,10 +1,37 @@
|
|
1
1
|
# QHash - [ActiveRecord](https://github.com/rails/rails/tree/main/activerecord) style query interface for Hash
|
2
2
|
|
3
3
|
[](https://github.com/AkihikoITOH/q_hash/actions/workflows/main.yml)
|
4
|
+
[](https://badge.fury.io/rb/q_hash)
|
4
5
|
[](https://codeclimate.com/github/AkihikoITOH/q_hash/maintainability)
|
5
6
|
|
6
7
|
QHash lets you query array of hashes with ActiveRecord-like interface.
|
7
8
|
|
9
|
+
## What's the point?
|
10
|
+
|
11
|
+
We often do something like
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
users.select do |user|
|
15
|
+
(dob = user.dig(:personal_data, :date_of_birth)) &&
|
16
|
+
dob > Date.new(1990, 1, 1) &&
|
17
|
+
user.dig(:address, :country) == "Germany" &&
|
18
|
+
user.dig(:address, :city) == "Hamburg"
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
which can quickly become hard to read.
|
23
|
+
|
24
|
+
QHash provides syntax sugar that would allow you to do
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
users.where(
|
28
|
+
personal_data: {
|
29
|
+
date_of_birth: ->(dob) { dob > Date.new(1990, 1, 1) }
|
30
|
+
},
|
31
|
+
address: {country: "Germany", city: "Hamburg"}
|
32
|
+
)
|
33
|
+
```
|
34
|
+
|
8
35
|
## Installation
|
9
36
|
|
10
37
|
Add this line to your application's Gemfile:
|
data/Rakefile
CHANGED
data/Steepfile
ADDED
data/bin/release
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env sh
|
2
|
+
|
3
|
+
GEM_VERSION=$(ruby -e '$LOAD_PATH << File.join(File.dirname(__FILE__), "lib"); require "q_hash"; print QHash::VERSION')
|
4
|
+
|
5
|
+
gem build q_hash.gemspec
|
6
|
+
|
7
|
+
if [ ! -d "pkg" ]; then
|
8
|
+
mkdir pkg
|
9
|
+
fi
|
10
|
+
|
11
|
+
mv q_hash-$GEM_VERSION.gem pkg/q_hash-$GEM_VERSION.gem
|
12
|
+
|
13
|
+
git tag -m "Release $GEM_VERSION" -a v$GEM_VERSION HEAD
|
14
|
+
git push origin --tags
|
15
|
+
|
16
|
+
gem push pkg/q_hash-$GEM_VERSION.gem
|
data/lib/q_hash.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class QHash
|
4
|
-
VERSION = "0.
|
4
|
+
VERSION = "0.2.0"
|
5
5
|
|
6
6
|
class Error < StandardError; end
|
7
7
|
|
@@ -13,18 +13,17 @@ class QHash
|
|
13
13
|
@data = data
|
14
14
|
end
|
15
15
|
|
16
|
-
def find_by(conditions)
|
17
|
-
data.find
|
18
|
-
conditions.all? { |key, value| query(hash, key, value) }
|
19
|
-
end
|
16
|
+
def find_by(**conditions)
|
17
|
+
data.find { |record| apply_conditions(record, conditions) }
|
20
18
|
end
|
21
19
|
|
22
|
-
def find_by!(conditions)
|
23
|
-
find_by(conditions) || raise(RecordNotFound)
|
20
|
+
def find_by!(**conditions)
|
21
|
+
find_by(**conditions) || raise(RecordNotFound)
|
24
22
|
end
|
25
23
|
|
26
|
-
def where(conditions)
|
27
|
-
|
24
|
+
def where(**conditions)
|
25
|
+
result = data.select { |record| apply_conditions(record, conditions) }
|
26
|
+
self.class.new(result)
|
28
27
|
end
|
29
28
|
|
30
29
|
def each(&block)
|
@@ -37,30 +36,24 @@ class QHash
|
|
37
36
|
|
38
37
|
private
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
attr_reader :data
|
40
|
+
|
41
|
+
def apply_conditions(record, conditions)
|
42
|
+
conditions.all? { |query_key, query_value| query(record, query_key, query_value) }
|
44
43
|
end
|
45
44
|
|
46
45
|
def query(record, key, value)
|
47
|
-
return false
|
46
|
+
return false unless record.key?(key)
|
48
47
|
|
49
48
|
case value
|
50
49
|
when Proc
|
51
50
|
value.call(record[key])
|
52
51
|
when Hash
|
53
|
-
value.all? { |
|
52
|
+
value.all? { |nested_query_key, nested_query_value| query(record[key], nested_query_key, nested_query_value) }
|
54
53
|
when Array
|
55
54
|
value.include?(record[key])
|
56
55
|
else
|
57
|
-
record[key]
|
56
|
+
value == record[key]
|
58
57
|
end
|
59
58
|
end
|
60
|
-
|
61
|
-
def top_level_keys
|
62
|
-
@top_level_keys ||= array_of_hashes.flat_map(&:keys).uniq
|
63
|
-
end
|
64
|
-
|
65
|
-
attr_reader :data, :filtered_data
|
66
59
|
end
|
data/sig/q_hash.rbs
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
2
|
+
class QHash
|
3
|
+
VERSION: String
|
4
|
+
|
5
|
+
Error: StandardError
|
6
|
+
RecordNotFound: StandardError
|
7
|
+
|
8
|
+
def initialize: (Array[Hash[Symbol, untyped]]) -> void
|
9
|
+
def find_by: (**Hash[Symbol, untyped]) -> Hash[Symbol, untyped]?
|
10
|
+
def find_by!: (**Hash[Symbol, untyped]) -> Hash[Symbol, untyped]?
|
11
|
+
def where: (**Hash[Symbol, untyped]) -> QHash
|
12
|
+
def each: () { (Hash[Symbol, untyped]) -> void } -> void
|
13
|
+
def inspect: () -> Array[Hash[Symbol, untyped]]
|
14
|
+
|
15
|
+
private attr_reader data: Array[Hash[Symbol, untyped]]
|
16
|
+
private def apply_conditions: (Hash[Symbol, untyped], Hash[Symbol, untyped]) -> bool
|
17
|
+
private def query: (Hash[Symbol, untyped], Symbol, untyped) -> bool
|
18
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: q_hash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akihiko Ito
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: QHash lets you query array of hashes with ActiveRecord-like interface
|
14
14
|
email:
|
@@ -28,10 +28,13 @@ files:
|
|
28
28
|
- LICENSE.txt
|
29
29
|
- README.md
|
30
30
|
- Rakefile
|
31
|
+
- Steepfile
|
31
32
|
- bin/console
|
33
|
+
- bin/release
|
32
34
|
- bin/setup
|
33
35
|
- lib/q_hash.rb
|
34
36
|
- q_hash.gemspec
|
37
|
+
- sig/q_hash.rbs
|
35
38
|
homepage: https://github.com/AkihikoITOH/q_hash
|
36
39
|
licenses:
|
37
40
|
- MIT
|