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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45090f151f081e5c9c4d6a744d745736f7a652a68d777886b87a0750fb8a4995
4
- data.tar.gz: 98a176a62849a2ba100a63c779ec2e4d815f699071dd6ecb0f91e5914a788c95
3
+ metadata.gz: 4b5ef11c5099019641fbe1de713e1be087f9775f58571cb87a1554ad0155956e
4
+ data.tar.gz: 4ddad57fda9b5b8ffdf078cf432ed1b5ebf960928be1058341a54ae567ad43f0
5
5
  SHA512:
6
- metadata.gz: 4512ee4a037ca7fc5dd0cca860d5ac35a8afdda22e76a99ef5a6b07c1dd8beb379edaf3c40664bc91badadf4e13ccc00b25d590b1941bad44b825fe6b164aa24
7
- data.tar.gz: a85e3d75b37ac15d953ce2e624597278b7c3df57906dc5eb88241d44d28216d87191905e00309add8201a3a7590e61d724cf226797574ad572dc7c04125141f2
6
+ metadata.gz: edc0f7958090f8cb5720385622759bdc840c88d348c4c9fc519f4496f264d2dc8b15ca2fe952f7da9441a21bf1ba30eec667d53554a9bd9d5170b917ff232e81
7
+ data.tar.gz: 13fb94e70543d0a5dfe64add5cefdab276d906df332e48386a78933dabd1dd04f52f1960118e5d0da1a7e9e228ef82c7387d437248de56a2db04fd13932aa674
@@ -16,5 +16,9 @@ jobs:
16
16
  with:
17
17
  ruby-version: ${{ matrix.ruby }}
18
18
  bundler-cache: true
19
- - name: Run the default task
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 "simplecov"
20
+ gem "steep"
data/Gemfile.lock CHANGED
@@ -1,20 +1,39 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- q_hash (0.1.2)
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.1.0)
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
- regexp_parser (2.3.0)
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.26.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.16.0, < 2.0)
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.16.0)
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.9.1)
54
- rubocop (= 1.26.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
  [![Ruby](https://github.com/AkihikoITOH/q_hash/actions/workflows/main.yml/badge.svg)](https://github.com/AkihikoITOH/q_hash/actions/workflows/main.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/q_hash.svg)](https://badge.fury.io/rb/q_hash)
4
5
  [![Maintainability](https://api.codeclimate.com/v1/badges/21e195471cca64af0366/maintainability)](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
@@ -7,4 +7,7 @@ RSpec::Core::RakeTask.new(:spec)
7
7
 
8
8
  require "standard/rake"
9
9
 
10
- task default: %i[standard spec]
10
+ task default: %i[standard spec steep]
11
+ task :steep do
12
+ sh "bundle exec steep check"
13
+ end
data/Steepfile ADDED
@@ -0,0 +1,7 @@
1
+ target :lib do
2
+ signature "sig"
3
+
4
+ check "lib"
5
+
6
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.strict)
7
+ end
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.1.2"
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 do |hash|
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
- self.class.new(filter_by_conditions(conditions))
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
- def filter_by_conditions(conditions)
41
- data.select do |hash|
42
- conditions.all? { |key, value| query(hash, key, value) }
43
- end
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 if record[key].nil?
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? { |nested_key, nested_value| query(record[key], nested_key, nested_value) }
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] == value
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.1.2
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-04-09 00:00:00.000000000 Z
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