yq 0.0.1 → 0.0.2

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
  SHA1:
3
- metadata.gz: b006998403bcb560004a4796d7d62d959eabb2c1
4
- data.tar.gz: 77b6a955d63ffdb64c4cb3ae8af5866fc736b165
3
+ metadata.gz: 3e23c35d91bbddf1f3e3dfa4a8de8059899303c7
4
+ data.tar.gz: f5afc4871b9483ce357dcf4d857595e7c46e3aa6
5
5
  SHA512:
6
- metadata.gz: c397cc7308ffb55641a523f7be3a0c411bc7e8f267f7b604bd3a9fcac989256817a205caa1b749822eb698e3c70059dd6b73106a2880a376744c17d8484a25e6
7
- data.tar.gz: 5aaba3f55ea899c0b53099d4042555bf8c828b6cefe81f4d0700fb0034339b1846e3c426600a093a603a96471b2a4ff2b858b2bc6d1efedec30f7f89deb0f4ff
6
+ metadata.gz: 9a0deb2bbf42f6e90fa203cc51ddd8927b5ad4813c6c9a078ae983ee5425b35c6d662cf577089bb408997be8641a6de94f02f3efc382f635f85278eafa210cbb
7
+ data.tar.gz: cd2a097c740d0d9309cd04e67fedbe0b2522926ee89e992cb2ee2635e5bfb5bfa01d90d994773d2b4edae4e12055736cf94cc5ab9d0c2aa1a6df209365fb14df
data/.gitignore CHANGED
@@ -115,3 +115,5 @@ Gemfile.lock
115
115
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
116
116
  .rvmrc
117
117
 
118
+ spec/helpers/failures.txt
119
+
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'jmespath'
3
+ gem 'contracts'
4
4
 
5
5
  group :development, :test do
6
6
  gem 'pry'
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Yq
2
2
 
3
- TODO: Write a gem description
3
+ Use `yq` to parse YAML documents using [JMESPath](http://jmespath.org/). This gem is a simple wrapper around the [jmespath gem](https://github.com/jmespath/jmespath.rb).
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,7 +20,20 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- TODO: Write usage instructions here
23
+ `yq` takes input from STDIN:
24
+
25
+ ```
26
+ $ cat stuff.yml | yq '.'
27
+ ---
28
+ stuff:
29
+ foo:
30
+ bar: baz
31
+
32
+ $ cat stuff.yml | yq 'stuff.foo'
33
+ ---
34
+ bar: baz
35
+
36
+ ```
24
37
 
25
38
  ## Contributing
26
39
 
data/bin/yq CHANGED
@@ -43,8 +43,10 @@ def prereqs
43
43
  raise "#{v} must be specified in the environment variables" unless ENV[v]
44
44
  end
45
45
 
46
+ raise "jq not installed" unless Yq.which('jq')
46
47
  end
47
48
 
49
+
48
50
  def start
49
51
  begin
50
52
  @yaml = $stdin.read
@@ -66,7 +68,6 @@ def develop
66
68
  LOGGER.level = Logger::DEBUG
67
69
  LOGGER.info "Develop mode"
68
70
  start
69
- binding.pry
70
71
  end
71
72
 
72
73
  def main_loop
data/lib/yq/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yq
2
- VERSION = "0.0.1"
2
+ VERSION = '0.0.2'
3
3
  end
data/lib/yq.rb CHANGED
@@ -1,19 +1,67 @@
1
1
  require "yq/version"
2
- require 'jmespath'
2
+ require 'open3'
3
+ require 'contracts'
3
4
  require 'stringio'
4
5
  require 'yaml'
6
+ require 'json'
7
+ require 'timeout'
5
8
 
6
9
  module Yq
10
+ def self.which(cmd)
11
+ exts = ENV['PATH'] ? ENV['PATH'].split(':') : ['']
12
+ exts.each { |ext|
13
+ exe = File.join(ext, cmd)
14
+ return exe if File.executable?(exe) && !File.directory?(exe)
15
+ }
16
+ return nil
17
+ end
18
+
7
19
  def self.search_yaml(query, yaml)
8
- hash = yaml_to_hash(yaml)
9
- resp_hash = search(query, hash)
10
- resp_yaml = hash_to_yaml(resp_hash)
20
+ req_json = yaml_to_json(yaml)
21
+ resp_json = search(query, req_json)
22
+ resp_yaml = json_to_yaml(resp_json)
11
23
  return resp_yaml
12
24
  end
13
25
 
14
- def self.search(query, hash)
15
- return hash if query == '.'
16
- JMESPath.search(query, hash)
26
+ def self.search(query, json)
27
+ cmd = which('jq') + %Q[ '#{query}']
28
+ input = json
29
+ output = ""
30
+ LOGGER.debug "sending jq #{cmd}"
31
+
32
+ Open3.popen2(cmd) do |i, o, t|
33
+ begin
34
+ pid = t.pid
35
+
36
+ if input
37
+ i.puts input
38
+ i.close
39
+ end
40
+
41
+ Timeout.timeout(5) do
42
+ o.each { |v|
43
+ output << v
44
+ }
45
+ end
46
+ rescue Timeout::Error
47
+ LOGGER.warn "Timing out #{t.inspect} after 1 second"
48
+ Process.kill(15, pid)
49
+ ensure
50
+ status = t.value
51
+ raise "JQ failed to exit cleanly" unless status.success?
52
+ end
53
+ end
54
+ return output
55
+ end
56
+
57
+ def self.yaml_to_json(yaml)
58
+ a = yaml_to_hash(yaml)
59
+ hash_to_json(a)
60
+ end
61
+
62
+ def self.json_to_yaml(json)
63
+ a = json_to_hash(json)
64
+ hash_to_yaml(a)
17
65
  end
18
66
 
19
67
  def self.yaml_to_hash(yaml)
@@ -23,4 +71,12 @@ module Yq
23
71
  def self.hash_to_yaml(hash)
24
72
  hash.to_yaml
25
73
  end
74
+
75
+ def self.json_to_hash(json)
76
+ JSON.parse(json)
77
+ end
78
+
79
+ def self.hash_to_json(hash)
80
+ hash.to_json
81
+ end
26
82
  end
data/spec/spec_helper.rb CHANGED
@@ -27,7 +27,7 @@ RSpec.configure do |config|
27
27
  config.default_formatter = 'doc'
28
28
  end
29
29
 
30
- config.order = :random
30
+ config.example_status_persistence_file_path = File.join(SPEC_ROOT, 'helpers', 'failures.txt')
31
31
 
32
32
  Kernel.srand config.seed
33
33
  end
data/spec/yq_bin_spec.rb CHANGED
@@ -56,16 +56,15 @@ describe 'bin/yq' do
56
56
  expect(status).to be_success
57
57
  end
58
58
 
59
- context 'parses' do
60
- let(:query) { 'foo.bar' }
59
+ describe 'parses' do
61
60
  let(:yaml) { <<-EOF }
62
61
  foo:
63
62
  bar:
64
63
  baz: value
65
64
  EOF
66
65
 
67
- it 'foo.bar' do
68
- out_err, status = run_bin(query, yaml)
66
+ it '.foo.bar' do
67
+ out_err, status = run_bin('.foo.bar', yaml)
69
68
  expect(out_err).to match('baz: value')
70
69
  expect(status).to be_success
71
70
  end
data/spec/yq_spec.rb CHANGED
@@ -1,48 +1,93 @@
1
1
  describe Yq do
2
2
  subject { described_class }
3
3
 
4
- let(:query) { 'foo.bar' }
5
-
6
- let (:hash) {
4
+ let(:hash) {
7
5
  { "foo" => { "bar" => { "baz" => "value" }}}
8
6
  }
9
7
 
10
- let (:yaml) {<<EOF}
8
+ let(:yaml) {<<EOF}
11
9
  foo:
12
10
  bar:
13
11
  baz: value
14
12
  EOF
15
13
 
16
- describe '#search' do
17
- subject { described_class.search(query, hash) }
14
+ let(:json) {<<EOF.chomp}
15
+ {"foo":{"bar":{"baz":"value"}}}
16
+ EOF
17
+
18
+ let(:jq_response) {<<EOF}
19
+ {
20
+ "baz": "value"
21
+ }
22
+ EOF
23
+
24
+ describe '.search' do
25
+ subject { described_class.search('.foo.bar', json) }
18
26
 
19
- it { is_expected.to match("baz" => "value") }
27
+ it { is_expected.to match(jq_response) }
20
28
 
21
- it 'passes it through to JMESPath' do
22
- expect(JMESPath).to receive(:search).with(query, hash)
29
+ it 'passes it through to jq' do
30
+ allow(Yq).to receive(:which).with('jq').and_return('/bin/jq')
31
+ expect(Open3).to receive(:popen2).with('/bin/jq .foo.bar').and_return(jq_response)
23
32
  subject
24
33
  end
25
34
 
26
- describe "'.'" do
27
- subject { described_class.search('.', hash) }
28
- it { is_expected.to match(hash) }
35
+ subject { described_class.search'.foobar', json }
36
+
37
+ it 'stops processing when jq exits uncleanly' do
38
+ # not mocking at this level, see implementation
29
39
  end
30
40
  end
31
41
 
32
- describe '#yaml_to_hash' do
42
+ describe '.yaml_to_hash' do
33
43
  subject { described_class.yaml_to_hash(yaml) }
34
44
  it { is_expected.to match(hash) }
35
45
  end
36
46
 
37
- describe '#hash_to_yaml' do
47
+ describe '.hash_to_yaml' do
38
48
  subject { described_class.hash_to_yaml(hash) }
39
49
  it { is_expected.to match(yaml) }
40
50
  end
41
51
 
42
- describe '#search_yaml' do
43
- subject { described_class.search_yaml(query, yaml) }
52
+ describe '.yaml_to_json' do
53
+ subject { described_class.yaml_to_json(yaml) }
54
+ it { is_expected.to match(json) }
55
+ end
56
+
57
+ describe '.json_to_yaml' do
58
+ subject { described_class.json_to_yaml(json) }
59
+ it { is_expected.to match(yaml) }
60
+ end
61
+
62
+ describe '.search_yaml' do
63
+ subject { described_class.search_yaml('.foo.bar', yaml) }
44
64
 
45
65
  it { is_expected.to match("baz: value") }
46
66
  end
47
67
 
68
+
69
+ describe '.which' do
70
+ subject { described_class.which('jq') }
71
+
72
+ before(:each) {
73
+ allow(ENV).to receive(:[]).with('PATH').and_return("/bin:/other/bin")
74
+ allow(File).to receive(:executable?).with("/bin/jq").and_return(false)
75
+ allow(File).to receive(:directory?).with("/bin/jq").and_return(false)
76
+ allow(File).to receive(:directory?).with("/other/bin/jq").and_return(false)
77
+ }
78
+
79
+ context 'but it does not exist' do
80
+ before(:each) {
81
+ allow(File).to receive(:executable?).with("/other/bin/jq").and_return(false)
82
+ }
83
+ it { is_expected.to be_falsey }
84
+ end
85
+
86
+ context 'and it does exist' do
87
+ before(:each) {
88
+ allow(File).to receive(:executable?).with("/other/bin/jq").and_return(true)
89
+ }
90
+ it { is_expected.to eq('/other/bin/jq') }
91
+ end
92
+ end
48
93
  end
data/yq.gemspec CHANGED
@@ -18,8 +18,6 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency 'jmespath'
22
-
23
21
  spec.add_development_dependency "bundler", "~> 1.7"
24
22
  spec.add_development_dependency "rake", "~> 10.0"
25
23
  spec.add_development_dependency "rspec", '~> 3.3'
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Park
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-10 00:00:00.000000000 Z
11
+ date: 2015-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: jmespath
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: bundler
29
15
  requirement: !ruby/object:Gem::Requirement