qig 0.1.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="