brat 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +3 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +24 -0
  6. data/README.md +103 -0
  7. data/Rakefile +9 -0
  8. data/bin/brat +7 -0
  9. data/brat.gemspec +26 -0
  10. data/lib/brat.rb +37 -0
  11. data/lib/brat/api.rb +17 -0
  12. data/lib/brat/cli.rb +47 -0
  13. data/lib/brat/cli_helpers.rb +175 -0
  14. data/lib/brat/client.rb +18 -0
  15. data/lib/brat/client/branches.rb +79 -0
  16. data/lib/brat/client/groups.rb +88 -0
  17. data/lib/brat/client/issues.rb +92 -0
  18. data/lib/brat/client/merge_requests.rb +107 -0
  19. data/lib/brat/client/milestones.rb +57 -0
  20. data/lib/brat/client/notes.rb +106 -0
  21. data/lib/brat/client/projects.rb +298 -0
  22. data/lib/brat/client/repositories.rb +78 -0
  23. data/lib/brat/client/snippets.rb +86 -0
  24. data/lib/brat/client/system_hooks.rb +58 -0
  25. data/lib/brat/client/users.rb +123 -0
  26. data/lib/brat/configuration.rb +40 -0
  27. data/lib/brat/error.rb +42 -0
  28. data/lib/brat/help.rb +44 -0
  29. data/lib/brat/objectified_hash.rb +24 -0
  30. data/lib/brat/request.rb +101 -0
  31. data/lib/brat/shell.rb +49 -0
  32. data/lib/brat/version.rb +3 -0
  33. data/spec/brat/cli_spec.rb +80 -0
  34. data/spec/brat/client/branches_spec.rb +103 -0
  35. data/spec/brat/client/groups_spec.rb +111 -0
  36. data/spec/brat/client/issues_spec.rb +122 -0
  37. data/spec/brat/client/merge_requests_spec.rb +124 -0
  38. data/spec/brat/client/milestones_spec.rb +66 -0
  39. data/spec/brat/client/notes_spec.rb +156 -0
  40. data/spec/brat/client/projects_spec.rb +357 -0
  41. data/spec/brat/client/repositories_spec.rb +92 -0
  42. data/spec/brat/client/snippets_spec.rb +85 -0
  43. data/spec/brat/client/system_hooks_spec.rb +69 -0
  44. data/spec/brat/client/users_spec.rb +192 -0
  45. data/spec/brat/objectified_hash_spec.rb +23 -0
  46. data/spec/brat/request_spec.rb +48 -0
  47. data/spec/brat_spec.rb +65 -0
  48. data/spec/fixtures/branch.json +1 -0
  49. data/spec/fixtures/branches.json +1 -0
  50. data/spec/fixtures/comment_merge_request.json +1 -0
  51. data/spec/fixtures/create_branch.json +1 -0
  52. data/spec/fixtures/create_merge_request.json +1 -0
  53. data/spec/fixtures/error_already_exists.json +1 -0
  54. data/spec/fixtures/group.json +60 -0
  55. data/spec/fixtures/group_create.json +1 -0
  56. data/spec/fixtures/group_member.json +1 -0
  57. data/spec/fixtures/group_member_delete.json +1 -0
  58. data/spec/fixtures/group_members.json +1 -0
  59. data/spec/fixtures/groups.json +2 -0
  60. data/spec/fixtures/issue.json +1 -0
  61. data/spec/fixtures/issues.json +1 -0
  62. data/spec/fixtures/key.json +1 -0
  63. data/spec/fixtures/keys.json +1 -0
  64. data/spec/fixtures/merge_request.json +1 -0
  65. data/spec/fixtures/merge_request_comments.json +1 -0
  66. data/spec/fixtures/merge_requests.json +1 -0
  67. data/spec/fixtures/milestone.json +1 -0
  68. data/spec/fixtures/milestones.json +1 -0
  69. data/spec/fixtures/note.json +1 -0
  70. data/spec/fixtures/notes.json +1 -0
  71. data/spec/fixtures/project.json +1 -0
  72. data/spec/fixtures/project_commit.json +13 -0
  73. data/spec/fixtures/project_commit_diff.json +10 -0
  74. data/spec/fixtures/project_commits.json +1 -0
  75. data/spec/fixtures/project_delete_key.json +8 -0
  76. data/spec/fixtures/project_events.json +1 -0
  77. data/spec/fixtures/project_for_user.json +1 -0
  78. data/spec/fixtures/project_fork_link.json +1 -0
  79. data/spec/fixtures/project_hook.json +1 -0
  80. data/spec/fixtures/project_hooks.json +1 -0
  81. data/spec/fixtures/project_issues.json +1 -0
  82. data/spec/fixtures/project_key.json +6 -0
  83. data/spec/fixtures/project_keys.json +6 -0
  84. data/spec/fixtures/project_tags.json +1 -0
  85. data/spec/fixtures/projects.json +1 -0
  86. data/spec/fixtures/protect_branch.json +1 -0
  87. data/spec/fixtures/session.json +1 -0
  88. data/spec/fixtures/snippet.json +1 -0
  89. data/spec/fixtures/snippets.json +1 -0
  90. data/spec/fixtures/system_hook.json +1 -0
  91. data/spec/fixtures/system_hook_test.json +1 -0
  92. data/spec/fixtures/system_hooks.json +1 -0
  93. data/spec/fixtures/tag.json +1 -0
  94. data/spec/fixtures/team_member.json +1 -0
  95. data/spec/fixtures/team_members.json +1 -0
  96. data/spec/fixtures/unprotect_branch.json +1 -0
  97. data/spec/fixtures/update_merge_request.json +1 -0
  98. data/spec/fixtures/user.json +1 -0
  99. data/spec/fixtures/users.json +1 -0
  100. data/spec/spec_helper.rb +74 -0
  101. metadata +281 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 057d5021e30f18c5dc02e68e144aac17b41d1cc9
4
+ data.tar.gz: 32c68c61399d306e309e36b2720a433fb9113a52
5
+ SHA512:
6
+ metadata.gz: b6a52cc17f8bece0515273aa515315bb96563997734772fa844a34b1d1e89f72b2f7354f78f52bdca0f2c7f91cd70818087650d056ed62e9047e46557bd46ee4
7
+ data.tar.gz: fcf7496ccd8efde5c835f1e03c49e0a6473ee851bd00843a3e3274adc5f90f80a9ce9a84f8d1b1cf355de606727f3d2b0065b6b1ffc0d122134cf32639b9d9b3
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea
19
+ .ruby-version
20
+ .ruby-gemset
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in brat.gemspec
4
+ gemspec
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2012-2014 Nihad Abbasov <mail@narkoz.me>
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,103 @@
1
+ # Brat
2
+
3
+ [website](http://brat.io/brat-io/brat)
4
+ [![build status](http://ci.brat.io/projects/7/status.png?ref=master)](http://ci.brat.io/projects/7?ref=master)
5
+
6
+ Brat is a wrapper and CLI for (Brat.io)[http://brat.io/brat-io/brat]. We are currently in pre-release.
7
+
8
+ ## Installation
9
+
10
+ Install it from rubygems:
11
+
12
+ ```sh
13
+ gem install brat
14
+ ```
15
+
16
+ Or add to a Gemfile:
17
+
18
+ ```ruby
19
+ gem 'brat'
20
+ # gem 'brat', :git => 'git://brat.io/brat-io/brat.git'
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ Rails Configuration example:
26
+
27
+ ```ruby
28
+ Brat.configure do |config|
29
+ config.private_token = 'qEsq1pt6HJPaNciie3MG' # user's private token, default: ENV['BRAT_API_PRIVATE_TOKEN']
30
+ # Optional
31
+ # config.endpoint = 'http://brat.io/api/v3' # API endpoint URL, default: 'http://brat.io/api/v3'
32
+ # config.user_agent = 'Custom User Agent' # user agent, default: 'Brat Ruby Gem [version]'
33
+ # config.sudo = 'user' # username for sudo mode, default: nil
34
+ end
35
+ ```
36
+
37
+ Usage examples:
38
+
39
+ ```ruby
40
+ # set a user private token
41
+ Brat.private_token = 'qEsq1pt6HJPaNciie3MG'
42
+ # => "qEsq1pt6HJPaNciie3MG"
43
+
44
+ # list projects
45
+ Brat.projects(:per_page => 5)
46
+ # => [#<Brat::ObjectifiedHash:0x000000023326e0 @data={"id"=>1, "code"=>"brute", "name"=>"Brute", "description"=>nil, "path"=>"brute", "default_branch"=>nil, "owner"=>#<Brat::ObjectifiedHash:0x00000002331600 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:56Z"}>, #<Brat::ObjectifiedHash:0x000000023450d8 @data={"id"=>2, "code"=>"mozart", "name"=>"Mozart", "description"=>nil, "path"=>"mozart", "default_branch"=>nil, "owner"=>#<Brat::ObjectifiedHash:0x00000002344ca0 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:57Z"}>, #<Brat::ObjectifiedHash:0x00000002344958 @data={"id"=>3, "code"=>"brat", "name"=>"Brat", "description"=>nil, "path"=>"brat", "default_branch"=>nil, "owner"=>#<Brat::ObjectifiedHash:0x000000023447a0 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:58Z"}>]
47
+
48
+ # initialize a new client
49
+ g = Brat.client(:endpoint => 'https://brat.io/api/v3', private_token: 'qEsq1pt6HJPaNciie3MG')
50
+ # => #<Brat::Client:0x00000001e62408 @endpoint="https://api.example.com", @private_token="qEsq1pt6HJPaNciie3MG", @user_agent="Brat Ruby Gem 0.1.1">
51
+
52
+ # get a user
53
+ user = g.user
54
+ # => #<Brat::ObjectifiedHash:0x00000002217990 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "bio"=>nil, "skype"=>"", "linkedin"=>"", "twitter"=>"john", "dark_scheme"=>false, "theme_id"=>1, "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>
55
+
56
+ # get a user's email
57
+ user.email
58
+ # => "john@example.com"
59
+
60
+ ```
61
+
62
+ ## CLI
63
+
64
+ Usage examples:
65
+
66
+ ```sh
67
+ # set your private_token
68
+ # list users
69
+ brat users
70
+
71
+ # get current user
72
+ brat user
73
+
74
+ # get a user
75
+ brat user 2
76
+
77
+ # filter output
78
+ brat user --only=id,username
79
+
80
+ brat user --except=email,bio
81
+ ```
82
+
83
+ ## CLI Shell
84
+
85
+ Usage examples:
86
+
87
+ ```sh
88
+ # start shell session
89
+ brat shell
90
+
91
+ # list available commands
92
+ brat> help
93
+
94
+ # list groups
95
+ brat> groups
96
+
97
+ # protect a branch
98
+ brat> protect_branch 1 master
99
+ ```
100
+
101
+ ## License
102
+
103
+ Released under the BSD 2-clause license. See LICENSE.txt for details.
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec) do |spec|
5
+ spec.pattern = FileList['spec/**/*_spec.rb']
6
+ spec.rspec_opts = ['--color', '--format d']
7
+ end
8
+
9
+ task :default => :spec
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'brat/cli'
6
+
7
+ Brat::CLI.start(ARGV)
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'brat/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "brat"
8
+ gem.version = Brat::VERSION
9
+ gem.authors = ["John-Henry Liberty"]
10
+ gem.email = ["johnhenry.liberty@gmail.com"]
11
+ gem.description = %q{Ruby client and CLI for Brat.io}
12
+ gem.summary = %q{A Ruby wrapper and CLI for the Brat.io API}
13
+ gem.homepage = "https://github.com/jhliberty/brat-cli"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_runtime_dependency 'httparty'
21
+ gem.add_runtime_dependency 'terminal-table'
22
+
23
+ gem.add_development_dependency 'rake'
24
+ gem.add_development_dependency 'rspec'
25
+ gem.add_development_dependency 'webmock'
26
+ end
@@ -0,0 +1,37 @@
1
+ require 'brat/version'
2
+ require 'brat/objectified_hash'
3
+ require 'brat/configuration'
4
+ require 'brat/error'
5
+ require 'brat/request'
6
+ require 'brat/api'
7
+ require 'brat/client'
8
+
9
+ module Brat
10
+ extend Configuration
11
+
12
+ # Alias for Brat::Client.new
13
+ #
14
+ # @return [Brat::Client]
15
+ def self.client(options={})
16
+ Brat::Client.new(options)
17
+ end
18
+
19
+ # Delegate to Brat::Client
20
+ def self.method_missing(method, *args, &block)
21
+ return super unless client.respond_to?(method)
22
+ client.send(method, *args, &block)
23
+ end
24
+
25
+ # Delegate to Brat::Client
26
+ def self.respond_to?(method)
27
+ return client.respond_to?(method) || super
28
+ end
29
+
30
+ # Returns an unsorted array of available client methods.
31
+ #
32
+ # @return [Array<Symbol>]
33
+ def self.actions
34
+ hidden = /endpoint|private_token|user_agent|sudo|get|post|put|\Adelete\z|validate|set_request_defaults/
35
+ (Brat::Client.instance_methods - Object.methods).reject {|e| e[hidden]}
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ module Brat
2
+ # @private
3
+ class API < Request
4
+ # @private
5
+ attr_accessor(*Configuration::VALID_OPTIONS_KEYS)
6
+
7
+ # Creates a new API.
8
+ # @raise [Error:MissingCredentials]
9
+ def initialize(options={})
10
+ options = Brat.options.merge(options)
11
+ Configuration::VALID_OPTIONS_KEYS.each do |key|
12
+ send("#{key}=", options[key])
13
+ end
14
+ set_request_defaults @endpoint, @private_token, @sudo
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,47 @@
1
+ require 'brat'
2
+ require 'terminal-table/import'
3
+ require_relative 'cli_helpers'
4
+ require_relative 'shell'
5
+
6
+ class Brat::CLI
7
+ extend Helpers
8
+
9
+ def self.start(args)
10
+ command = args.shift.strip rescue 'help'
11
+ run(command, args)
12
+ end
13
+
14
+ def self.run(cmd, args=[])
15
+ case cmd
16
+ when 'help'
17
+ puts actions_table
18
+ when 'info'
19
+ endpoint = Brat.endpoint ? Brat.endpoint : 'not set'
20
+ private_token = Brat.private_token ? Brat.private_token : 'not set'
21
+ puts "Brat endpoint is #{endpoint}"
22
+ puts "Brat private token is #{private_token}"
23
+ puts "Ruby Version is #{RUBY_VERSION}"
24
+ puts "Brat Ruby Gem #{Brat::VERSION}"
25
+ when '-v', '--version'
26
+ puts "Brat Ruby Gem #{Brat::VERSION}"
27
+ when 'shell'
28
+ Brat::Shell.start
29
+ else
30
+ unless valid_command?(cmd)
31
+ puts "Unknown command. Run `brat help` for a list of available commands."
32
+ exit(1)
33
+ end
34
+
35
+ if args.any? && (args.last.start_with?('--only=') || args.last.start_with?('--except='))
36
+ command_args = args[0..-2]
37
+ else
38
+ command_args = args
39
+ end
40
+
41
+ confirm_command(cmd)
42
+
43
+ data = brat_helper(cmd, command_args) { exit(1) }
44
+ output_table(cmd, args, data)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,175 @@
1
+ class Brat::CLI
2
+ # Defines methods related to CLI output and formatting.
3
+ module Helpers
4
+ extend self
5
+
6
+ # Returns filtered required fields.
7
+ #
8
+ # @return [Array]
9
+ def required_fields(args)
10
+ if args.any? && args.last.start_with?('--only=')
11
+ args.last.gsub('--only=', '').split(',')
12
+ else
13
+ []
14
+ end
15
+ end
16
+
17
+ # Returns filtered excluded fields.
18
+ #
19
+ # @return [Array]
20
+ def excluded_fields(args)
21
+ if args.any? && args.last.start_with?('--except=')
22
+ args.last.gsub('--except=', '').split(',')
23
+ else
24
+ []
25
+ end
26
+ end
27
+
28
+ # Confirms command is valid.
29
+ #
30
+ # @return [Boolean]
31
+ def valid_command?(cmd)
32
+ command = cmd.is_a?(Symbol) ? cmd : cmd.to_sym
33
+ Brat.actions.include?(command)
34
+ end
35
+
36
+ # Confirms command with a desctructive action.
37
+ #
38
+ # @return [String]
39
+ def confirm_command(cmd)
40
+ if cmd.start_with?('remove_') || cmd.start_with?('delete_')
41
+ puts "Are you sure? (y/n)"
42
+ if %w(y yes).include?($stdin.gets.to_s.strip.downcase)
43
+ puts 'Proceeding..'
44
+ else
45
+ puts 'Command aborted.'
46
+ exit(1)
47
+ end
48
+ end
49
+ end
50
+
51
+ # Table with available commands.
52
+ #
53
+ # @return [String]
54
+ def actions_table
55
+ client = Brat::Client.new(endpoint: '')
56
+ actions = Brat.actions
57
+ methods = []
58
+
59
+ actions.each do |action|
60
+ methods << {
61
+ name: action,
62
+ owner: client.method(action).owner.to_s.gsub('Brat::Client::', '')
63
+ }
64
+ end
65
+
66
+ owners = methods.map {|m| m[:owner]}.uniq.sort
67
+ methods_c = methods.group_by {|m| m[:owner]}
68
+ methods_c = methods_c.map {|_, v| [_, v.sort_by {|hv| hv[:name]}] }
69
+ methods_c = Hash[methods_c.sort_by(&:first).map {|k, v| [k, v]}]
70
+ max_column_length = methods_c.values.max_by(&:size).size
71
+
72
+ rows = max_column_length.times.map do |i|
73
+ methods_c.keys.map do |key|
74
+ methods_c[key][i] ? methods_c[key][i][:name] : ''
75
+ end
76
+ end
77
+
78
+ table do |t|
79
+ t.title = "Available commands (#{actions.size} total)"
80
+ t.headings = owners
81
+
82
+ rows.each do |row|
83
+ t.add_row row
84
+ end
85
+ end
86
+ end
87
+
88
+ # Decides which table to use.
89
+ #
90
+ # @return [String]
91
+ def output_table(cmd, args, data)
92
+ case data
93
+ when Brat::ObjectifiedHash
94
+ puts single_record_table(data, cmd, args)
95
+ when Array
96
+ puts multiple_record_table(data, cmd, args)
97
+ else
98
+ puts data.inspect
99
+ end
100
+ end
101
+
102
+ # Table for a single record.
103
+ #
104
+ # @return [String]
105
+ def single_record_table(data, cmd, args)
106
+ hash = data.to_h
107
+ keys = hash.keys.sort {|x, y| x.to_s <=> y.to_s }
108
+ keys = keys & required_fields(args) if required_fields(args).any?
109
+ keys = keys - excluded_fields(args)
110
+
111
+ table do |t|
112
+ t.title = "Brat.#{cmd} #{args.join(', ')}"
113
+
114
+ keys.each_with_index do |key, index|
115
+ case value = hash[key]
116
+ when Hash
117
+ value = 'Hash'
118
+ when nil
119
+ value = 'null'
120
+ end
121
+
122
+ t.add_row [key, value]
123
+ t.add_separator unless keys.size - 1 == index
124
+ end
125
+ end
126
+ end
127
+
128
+ # Table for multiple records.
129
+ #
130
+ # @return [String]
131
+ def multiple_record_table(data, cmd, args)
132
+ return 'No data' if data.empty?
133
+
134
+ arr = data.map(&:to_h)
135
+ keys = arr.first.keys.sort {|x, y| x.to_s <=> y.to_s }
136
+ keys = keys & required_fields(args) if required_fields(args).any?
137
+ keys = keys - excluded_fields(args)
138
+
139
+ table do |t|
140
+ t.title = "Brat.#{cmd} #{args.join(', ')}"
141
+ t.headings = keys
142
+
143
+ arr.each_with_index do |hash, index|
144
+ values = []
145
+
146
+ keys.each do |key|
147
+ case value = hash[key]
148
+ when Hash
149
+ value = 'Hash'
150
+ when nil
151
+ value = 'null'
152
+ end
153
+
154
+ values << value
155
+ end
156
+
157
+ t.add_row values
158
+ t.add_separator unless arr.size - 1 == index
159
+ end
160
+ end
161
+ end
162
+
163
+ # Helper function to call Brat commands with args.
164
+ def brat_helper(cmd, args=[])
165
+ begin
166
+ data = args.any? ? Brat.send(cmd, *args) : Brat.send(cmd)
167
+ rescue => e
168
+ puts e.message
169
+ yield if block_given?
170
+ end
171
+
172
+ data
173
+ end
174
+ end
175
+ end