qig 0.1.2 → 0.4.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: 3f7c37c8a295eb210423179f2f0e7770dade31d4ceaabde0c1332b34e11ab443
4
- data.tar.gz: 8cfc282e7cbc383686f132030b4f07adbce7738475d7bfd3b88b04f221d1f371
3
+ metadata.gz: 56ef9b278c456d21a26c5aa5c4af9c3fd44ac5c5b8ebc6f680d528c2380e1af3
4
+ data.tar.gz: c5bee04e6937170225b362ae777a7456c488b85afec37695fd5167530d0eaa13
5
5
  SHA512:
6
- metadata.gz: b8c7bf8e33ecc7f57e9fa3f7760c4c89ebd7150bc446d32ef3062b415be2db4a7df198595c8cd8c54655fe62a745092294227e905fb4efad4f477ad5c0c37631
7
- data.tar.gz: dbeb18f978e6db504841031529e138d958583a3d683abb1c15b0fce0f597ee7e1bc7ef7e22aa0b05e9368bba45c229b84b01825984fddc791180fb62ad383e8b
6
+ metadata.gz: f01814583296ea94b8839b6fb057b27880c92dc23870d533c192d1ed36a34a6d9650a58390f1c5e85cc2a6d92ed3356678f7bb069419015416087df208890d19
7
+ data.tar.gz: c4b2a0d910a66ba27e2b6f24963e015b404759c092f1915126d3c7aebccdf50205d6ab96e6ee480ef20709e361e475bf27b9702f0918b7fded24762e12766526
data/.rubocop.yml CHANGED
@@ -1,5 +1,12 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.6
2
+ TargetRubyVersion: 2.7
3
+ NewCops: enable
3
4
 
4
5
  Layout/LineLength:
5
6
  Max: 120
7
+
8
+ Metrics/BlockLength:
9
+ IgnoredMethods: ['describe', 'context']
10
+
11
+ Style/DocumentationMethod:
12
+ Enabled: true
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown
data/CHANGELOG.md CHANGED
@@ -1,3 +1,64 @@
1
+ # 0.4.0 (Jan 27, 2022)
2
+
3
+ ## Features
4
+
5
+ - `Qig::Qiggable` mixin for adding chainable `.qig` syntax to subject classes.
6
+ - Allow stepping into enumerables.
7
+
8
+ ## Fixes
9
+
10
+ - make unboxing (`[]`) compatible with `Enumerable`. Previously in collection-context this used `flatten(1)`, which
11
+ `Enumerable` does not support. Now uses `flat_map(&:itself)` instead
12
+
13
+ ## Documentation
14
+
15
+ - Literate spec covering compatibility with lazy enumerators.
16
+
17
+ # 0.3.0 (January 24, 2022)
18
+
19
+ ## BREAKING CHANGES
20
+
21
+ - drop ruby 2.6 support, because Ruby 2.6 will be EOL in 2 months, and Ruby 2.7 pattern matching syntax makes
22
+ command parsing cases *much* easier to maintain, keeping the main switching logic a single-level `case`
23
+
24
+ ## Features
25
+
26
+ - method invocation syntax (e.g. for filtering)
27
+ - quoting syntax to use operators as literal keys
28
+ - reboxing operator or value collection operator, inverse of the value iteration operator
29
+
30
+ ## Documentation
31
+
32
+ - Reorganize and explain literate specs
33
+ - Specs for dig conformance
34
+
35
+ ## Fixes
36
+
37
+ - On invalid access to struct, return nil, for better conformance to Struct#dig. Previously this raised error.
38
+
39
+ # 0.2.0 (January 14, 2022)
40
+
41
+ ## Features
42
+
43
+ - Value iteration(`[]` over hashes)
44
+
45
+ ## Documentation
46
+
47
+ - Initial yard documentation on method and module
48
+ - Document and spec that we can qig into Structs and OpenStructs
49
+
50
+ # 0.1.3 (January 13, 2022)
51
+
52
+ ## Documentation
53
+
54
+ - fix changelog uri (again)
55
+
56
+ # 0.1.2 (January 13, 2022)
57
+
58
+ ## Documentation
59
+
60
+ - fix changelog uri
61
+
1
62
  # 0.1.1 (January 13, 2022)
2
63
 
3
64
  ## Documentation
@@ -10,4 +71,4 @@
10
71
  ## Features
11
72
 
12
73
  - Ability to qig into arrays and hashes
13
- - Value iteration (`[]`) over arrays
74
+ - Value iteration (`[]`) over arrays
data/Gemfile CHANGED
@@ -5,10 +5,11 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in qig.gemspec
6
6
  gemspec
7
7
 
8
+ gem 'pry', '~> 0.14.1'
8
9
  gem 'rake', '~> 13.0'
9
-
10
10
  gem 'rspec', '~> 3.0'
11
-
11
+ gem 'rspec_junit_formatter', '~> 0.5.1'
12
12
  gem 'rubocop', '~> 1.21'
13
-
14
- gem "pry", "~> 0.14.1"
13
+ gem 'rubocop-rake', '~> 0.6.0'
14
+ gem 'rubocop-rspec', '~> 2.7'
15
+ gem 'yard', '~> 0.9.27'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- qig (0.1.2)
4
+ qig (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -33,6 +33,8 @@ GEM
33
33
  diff-lcs (>= 1.2.0, < 2.0)
34
34
  rspec-support (~> 3.10.0)
35
35
  rspec-support (3.10.3)
36
+ rspec_junit_formatter (0.5.1)
37
+ rspec-core (>= 2, < 4, != 2.12.0)
36
38
  rubocop (1.24.1)
37
39
  parallel (~> 1.10)
38
40
  parser (>= 3.0.0.0)
@@ -44,8 +46,15 @@ GEM
44
46
  unicode-display_width (>= 1.4.0, < 3.0)
45
47
  rubocop-ast (1.15.1)
46
48
  parser (>= 3.0.1.1)
49
+ rubocop-rake (0.6.0)
50
+ rubocop (~> 1.0)
51
+ rubocop-rspec (2.7.0)
52
+ rubocop (~> 1.19)
47
53
  ruby-progressbar (1.11.0)
48
54
  unicode-display_width (2.1.0)
55
+ webrick (1.7.0)
56
+ yard (0.9.27)
57
+ webrick (~> 1.7.0)
49
58
 
50
59
  PLATFORMS
51
60
  x86_64-linux
@@ -55,7 +64,11 @@ DEPENDENCIES
55
64
  qig!
56
65
  rake (~> 13.0)
57
66
  rspec (~> 3.0)
67
+ rspec_junit_formatter (~> 0.5.1)
58
68
  rubocop (~> 1.21)
69
+ rubocop-rake (~> 0.6.0)
70
+ rubocop-rspec (~> 2.7)
71
+ yard (~> 0.9.27)
59
72
 
60
73
  BUNDLED WITH
61
74
  2.3.4
data/README.md CHANGED
@@ -1,17 +1,39 @@
1
1
  # Qig
2
2
 
3
- qig is dig extended with jq's "value iterator" `[]` operator.
3
+ [![Gem Version](https://badge.fury.io/rb/qig.svg)](https://badge.fury.io/rb/qig)
4
+ [![CircleCI](https://circleci.com/gh/NAR8789/qig-ruby/tree/main.svg?style=shield)](https://circleci.com/gh/NAR8789/qig-ruby/tree/main)
5
+
6
+ qig is dig extended with jq's "value iterator" `[]` operator and some other goodies.
7
+
8
+ ## Usage
9
+
10
+ ```ruby
11
+ Qig.qig(subject, *path) # => contents of subject at path
12
+ ```
13
+
14
+ examples:
15
+ ```ruby
16
+ # dig-like usage
17
+ Qig.qig({a: { b: { c: 1 } } }, :a, :b, :c) # => 1
18
+
19
+ # dig-like usage augmented with jq's [] operator
20
+ Qig.qig({a: { b: [ { c: 1 }, { c: 2 } ] } }, :a, :b, [], :c) # => [1, 2]
21
+
22
+ # after expanding values, collect them back into an array for indexing into with `[[]]`
23
+ Qig.qig({ a: { b: [{ c: 1 }, { c: 2 }] } }, :a, :b, [], :c, [[]], 1) # => 2
24
+ ```
25
+
26
+ More documentation in the [literate specs](spec/literate)
4
27
 
5
28
  ## Features
6
29
 
7
- - [x] qig into arrays and hashes
8
- - [ ] qig into structs
9
- - [ ] qig into OpenStructs
10
- - [ ] qig into CSV::Tables
11
- - [ ] qig into CSV::Rows
12
- - [x] value iteration over arrays
13
- - [ ] value iteration over hashes
14
- - [ ] option to monkey patch this for more dig-like `subject.qig(*path)` syntax
30
+ - [x] compatible with dig (see (dig conformance specs)[spec/literate/qig/02_conformance/dig_conformance_spec.rb])
31
+ - [x] jq-like value iteration (`[]` operator)
32
+ - [x] invoke ruby methods during inside the filter chain
33
+ - [x] value collect: `[[]]`, inverse of the `[]` operator. Collect streamed values back into an array
34
+ - [x] `Qig::Qiggable` mixin for more dig-like `subject.qig(*path)` syntax
35
+ - [ ] extensive literate specs
36
+ - [ ] works with lazy collections
15
37
 
16
38
  ## Installation
17
39
 
@@ -29,18 +51,6 @@ Or install it yourself as:
29
51
 
30
52
  $ gem install qig
31
53
 
32
- ## Usage
33
-
34
- ```ruby
35
- Qig.qig(subject, *path) # => contents of subject at path
36
- ```
37
-
38
- examples:
39
- ```ruby
40
- Qig.qig({a: { b: { c: 1 } } }, :a, :b, :c) # => 1
41
- Qig.qig({a: { b: [ { c: 1 }, { c: 2 } ] } }, :a, :b, [], :c) # => [1, 2]
42
- ```
43
-
44
54
  ## Development
45
55
 
46
56
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/bin/console CHANGED
@@ -7,5 +7,5 @@ require 'qig'
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
9
9
 
10
- require "pry"
10
+ require 'pry'
11
11
  Pry.start
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Qig
4
+ # mix-in to add a `.qig` method to any class.
5
+ # NOTE: Target class should support `#[]`, `#map`, and either `#flat_map` or `#values` for full qig functionality
6
+ # - `#[]`: used for stepping in unit context
7
+ # - `#map`: used for stepping in collection context
8
+ # - `#flat_map` or `#values`: used for unboxing in collection context
9
+ module Qiggable
10
+ # @param path [Array<String, Symbol, Array, Object>] retrieval path to apply to `subject`
11
+ #
12
+ # @return [Object, Array<Object>] the value(s) of `self` located at `path`
13
+ def qig(*path)
14
+ Qig.qig(self, *path)
15
+ end
16
+
17
+ # see Enumerable#lazy
18
+ #
19
+ # This version extends the underlying lazy enumerable with Qig::Qiggable
20
+ def lazy
21
+ super.extend(Qig::Qiggable)
22
+ end
23
+ end
24
+ end
data/lib/qig/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Qig
4
- VERSION = '0.1.2'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/qig.rb CHANGED
@@ -2,39 +2,100 @@
2
2
 
3
3
  require_relative 'qig/version'
4
4
 
5
+ # Combining the powers of `dig` and `jq`.
6
+ # Qig is dig extended with jq's value iteration `[]` operator.
5
7
  module Qig
6
- def self.qig(*args)
7
- unit_qig(*args)
8
- end
8
+ autoload :Qiggable, 'qig/qiggable.rb'
9
9
 
10
- def self.unit_qig(subject, *path)
11
- return subject if subject.nil?
12
-
13
- head, *rest = path
14
- case head
15
- when nil
16
- subject
17
- when []
18
- collection_qig(subject, *rest)
19
- # hmm... what should happen if I [] on something not an array?
20
- else
21
- unit_qig(subject[head], *rest)
10
+ class << self
11
+ # @param subject [Array, Hash, #[]] `subject` to be qug into.
12
+ # @param path [Array<String, Symbol, Array, Object>] retrieval path to apply to `subject`
13
+ #
14
+ # @return [Object, Array<Object>] the value(s) of `subject` located at `path`
15
+ def qig(subject, *path)
16
+ unit_qig(subject, *path)
17
+ end
18
+
19
+ # "values" as in jq's "value iterator".
20
+ #
21
+ # Coerce to array by taking the .values. Intuitively, get all possible values of `arrayish[x]`.
22
+ #
23
+ # @param arrayish [Array, Hash, #values, Object] array or hash or other to coerce to values
24
+ # @return [Array, Array, Array, Object] array of coerced values
25
+ def values(arrayish)
26
+ arrayish.respond_to?(:values) ? arrayish.values : arrayish
27
+ end
28
+
29
+ private
30
+
31
+ def unit_qig(subject, *path) # rubocop:disable Metrics/MethodLength
32
+ head, *rest = path
33
+ case head
34
+ in nil
35
+ subject
36
+ in []
37
+ collection_qig(values(subject), *rest)
38
+ in [[]]
39
+ unit_qig([subject], *rest)
40
+ in ['', key]
41
+ unit_qig(step(subject, key), *rest)
42
+ in [[method, [*args], block]]
43
+ unit_qig(subject.public_send(method, *args, &block), *rest)
44
+ in [[method, [*args]]]
45
+ unit_qig(subject.public_send(method, *args), *rest)
46
+ in [[method]]
47
+ unit_qig(subject.public_send(method), *rest)
48
+ in [method, *]
49
+ raise ArgumentError, 'stream method invocation not applicable in unit context'
50
+ else
51
+ unit_qig(step(subject, head), *rest)
52
+ end
53
+ end
54
+
55
+ def collection_qig(subjects, *path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
56
+ head, *rest = path
57
+ case head
58
+ in nil
59
+ subjects
60
+ in []
61
+ collection_qig(subjects.map(&method(:values)).flat_map(&:itself), *rest)
62
+ in [[]]
63
+ unit_qig(subjects, *rest)
64
+ in ['', key]
65
+ collection_qig(subjects.map { |s| step(s, key) }, *rest)
66
+ in [[method, [*args], block]]
67
+ collection_qig(subjects.map { |s| s.public_send(method, *args, &block) }, *rest)
68
+ in [[method, [*args]]]
69
+ collection_qig(subjects.map { |s| s.public_send(method, *args) }, *rest)
70
+ in [[method]]
71
+ collection_qig(subjects.map { |s| s.public_send(method) }, *rest)
72
+ in [method, [*args], block]
73
+ collection_qig(subjects.public_send(method, *args, &block), *rest)
74
+ in [method, [*args]]
75
+ collection_qig(subjects.public_send(method, *args), *rest)
76
+ in [method]
77
+ collection_qig(subjects.public_send(method), *rest)
78
+ else
79
+ collection_qig(subjects.map { |s| step(s, head) }, *rest)
80
+ end
22
81
  end
23
- end
24
82
 
25
- def self.collection_qig(subjects, *path)
26
- return subjects if subjects.empty?
27
-
28
- head, *rest = path
29
- case head
30
- when nil
31
- subjects
32
- when []
33
- collection_qig(subjects.flatten(1), *rest)
34
- # not sure this is quite jq-compliant... [] refuses to iterate over atoms, but flatten will just preserve them.
35
- # maybe more in the spirit of `dig` though?
36
- else
37
- collection_qig(subjects.map { |e| e.nil? ? e : e[head] }, *rest)
83
+ def step(subject, key)
84
+ case subject
85
+ in Enumerable unless subject.respond_to?(:[])
86
+ case key
87
+ in Integer
88
+ subject.drop(key).first
89
+ in Range
90
+ subject.drop(key.begin).take(key.count)
91
+ end
92
+ else
93
+ subject&.[](key)
94
+ end
95
+ rescue NameError, IndexError
96
+ # Struct's [] is strict and raises on missing key.
97
+ # TODO: more efficient / prettier way of doing this. How does struct itself implement dig?
98
+ nil
38
99
  end
39
100
  end
40
101
  end
data/qig.gemspec CHANGED
@@ -12,11 +12,11 @@ Gem::Specification.new do |spec|
12
12
  # spec.description = "TODO: Write a longer description or delete this line."
13
13
  spec.homepage = 'https://github.com/NAR8789/qig-ruby'
14
14
  spec.license = 'MIT'
15
- spec.required_ruby_version = '>= 2.6.0'
15
+ spec.required_ruby_version = '>= 2.7.0'
16
16
 
17
17
  spec.metadata['homepage_uri'] = spec.homepage
18
18
  spec.metadata['source_code_uri'] = spec.homepage
19
- spec.metadata['changelog_uri'] = "#{spec.homepage}/CHANGELOG.md"
19
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
20
20
 
21
21
  # Specify which files should be added to the gem when it is released.
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
34
34
 
35
35
  # For more information and examples about making a new gem, check out our
36
36
  # guide at: https://bundler.io/guides/creating_gem.html
37
+ spec.metadata['rubygems_mfa_required'] = 'true'
37
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qig
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xiao Fan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-13 00:00:00.000000000 Z
11
+ date: 2022-01-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -19,6 +19,7 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - ".rspec"
21
21
  - ".rubocop.yml"
22
+ - ".yardopts"
22
23
  - CHANGELOG.md
23
24
  - CODE_OF_CONDUCT.md
24
25
  - Gemfile
@@ -29,6 +30,7 @@ files:
29
30
  - bin/console
30
31
  - bin/setup
31
32
  - lib/qig.rb
33
+ - lib/qig/qiggable.rb
32
34
  - lib/qig/version.rb
33
35
  - qig.gemspec
34
36
  - sig/qig.rbs
@@ -38,7 +40,8 @@ licenses:
38
40
  metadata:
39
41
  homepage_uri: https://github.com/NAR8789/qig-ruby
40
42
  source_code_uri: https://github.com/NAR8789/qig-ruby
41
- changelog_uri: https://github.com/NAR8789/qig-ruby/CHANGELOG.md
43
+ changelog_uri: https://github.com/NAR8789/qig-ruby/blob/main/CHANGELOG.md
44
+ rubygems_mfa_required: 'true'
42
45
  post_install_message:
43
46
  rdoc_options: []
44
47
  require_paths:
@@ -47,7 +50,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
47
50
  requirements:
48
51
  - - ">="
49
52
  - !ruby/object:Gem::Version
50
- version: 2.6.0
53
+ version: 2.7.0
51
54
  required_rubygems_version: !ruby/object:Gem::Requirement
52
55
  requirements:
53
56
  - - ">="