nrser-rash 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +104 -0
- data/.gitmodules +4 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/.yardopts +7 -0
- data/Gemfile +10 -0
- data/README.md +4 -0
- data/Rakefile +6 -0
- data/bash/source-profile.sh +17 -0
- data/dev/bin/.gitkeep +0 -0
- data/dev/bin/console +33 -0
- data/dev/bin/rake +3 -0
- data/dev/bin/rash +16 -0
- data/dev/bin/rspec +3 -0
- data/dev/ref/autocomplete.rb +62 -0
- data/dev/scratch/apps.AppleScript +14 -0
- data/dev/scratch/blocks.rb +232 -0
- data/dev/scratch/decorating_methods.rb +18 -0
- data/dev/scratch/functions.sh +80 -0
- data/dev/scratch/if.sh +16 -0
- data/dev/scratch/inc.rb +3 -0
- data/dev/scratch/inheriting_env/main.rb +44 -0
- data/dev/scratch/inheriting_env/sub.rb +9 -0
- data/dev/scratch/load_main.rb +5 -0
- data/dev/scratch/load_module.rb +19 -0
- data/dev/scratch/lsregister-dump.txt +30165 -0
- data/dev/scratch/main.rb +4 -0
- data/dev/scratch/optparse.rb +43 -0
- data/dev/scratch/overridding-cd.sh +53 -0
- data/dev/scratch/path.sh +22 -0
- data/dev/scratch/pirating_methods.rb +62 -0
- data/dev/scratch/profile.sh +624 -0
- data/dev/scratch/return.sh +5 -0
- data/dev/scratch/source_rvm.sh +11 -0
- data/dev/scratch/stub-names/project/test +3 -0
- data/exe/rash +4 -0
- data/lib/nrser/rash/cli/call.rb +137 -0
- data/lib/nrser/rash/cli/help.rb +29 -0
- data/lib/nrser/rash/cli/list.rb +36 -0
- data/lib/nrser/rash/cli/run.rb +54 -0
- data/lib/nrser/rash/cli.rb +21 -0
- data/lib/nrser/rash/config.rb +172 -0
- data/lib/nrser/rash/core_ext/object.rb +55 -0
- data/lib/nrser/rash/formatters.rb +105 -0
- data/lib/nrser/rash/functions.rb +154 -0
- data/lib/nrser/rash/helpers.rb +53 -0
- data/lib/nrser/rash/testing.rb +305 -0
- data/lib/nrser/rash/util.rb +260 -0
- data/lib/nrser/rash/version.rb +17 -0
- data/lib/nrser/rash.rb +40 -0
- data/nrser-rash.gemspec +48 -0
- data/tmp/.gitkeep +0 -0
- metadata +248 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
using NRSER
|
8
|
+
using NRSER::Types
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
module NRSER::Rash::CLI
|
15
|
+
|
16
|
+
# Call a Rash function.
|
17
|
+
#
|
18
|
+
# @param [String] name
|
19
|
+
# Name of the function.
|
20
|
+
#
|
21
|
+
# @param [Array<String>] argv
|
22
|
+
# The shell arguments.
|
23
|
+
#
|
24
|
+
def self.call name, argv
|
25
|
+
|
26
|
+
logger.trace "calling #{ name.inspect }, argv: #{ argv.inspect }"
|
27
|
+
# look for options
|
28
|
+
options = {}
|
29
|
+
args = argv.reject do |arg|
|
30
|
+
# long options of form '--<name>=<value>'
|
31
|
+
if m = arg.match(/\A--([^=]*)(=?)(.*)/)
|
32
|
+
options[m[1].to_sym] = if m[2] == ''
|
33
|
+
true
|
34
|
+
else
|
35
|
+
m[3]
|
36
|
+
end
|
37
|
+
true
|
38
|
+
# short options of form '-<char>'
|
39
|
+
elsif arg.start_with? '-'
|
40
|
+
arg[1..-1].each_char do |char|
|
41
|
+
options[char] = true
|
42
|
+
end
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
logger.debug "options: #{ options.inspect }"
|
47
|
+
# options are the last arg, unless we didn't find any
|
48
|
+
#
|
49
|
+
# NOTE: this causes functions without an optional `options` arg
|
50
|
+
# on the end to raise an exception when called with any options.
|
51
|
+
#
|
52
|
+
# i think this is the correct behavior: the function can't handle
|
53
|
+
# options, and should error out.
|
54
|
+
args << options unless options.empty?
|
55
|
+
|
56
|
+
NRSER::Rash.load_functions
|
57
|
+
if name.include? '.'
|
58
|
+
namespace, method_name = name.split '.'
|
59
|
+
namespace = namespace.split '::'
|
60
|
+
else
|
61
|
+
namespace = []
|
62
|
+
method_name = name
|
63
|
+
end
|
64
|
+
mod = NRSER::Rash::Functions
|
65
|
+
namespace.each do |submod_name|
|
66
|
+
mod = mod.const_get(submod_name.capitalize)
|
67
|
+
end
|
68
|
+
begin
|
69
|
+
rtn = mod.method(method_name).call *args
|
70
|
+
rescue Exception => error
|
71
|
+
if NRSER::Rash.config( 'PRINT_ERRORS' ).truthy?
|
72
|
+
if NRSER::Rash.config( 'STACKTRACE' ).truthy?
|
73
|
+
raise error
|
74
|
+
else
|
75
|
+
logger.fatal error
|
76
|
+
# this is the error code that ruby seems to exit with when you
|
77
|
+
# don't check the exception
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
logger.debug "return value: #{ rtn.inspect }"
|
83
|
+
if formatted = format(rtn)
|
84
|
+
puts formatted
|
85
|
+
end
|
86
|
+
exit 0
|
87
|
+
end
|
88
|
+
|
89
|
+
# formats an object to write to `$stdout`.
|
90
|
+
# returns `nil` if there's nothing to write (different than returning '',
|
91
|
+
# indicating the empty string should be written).
|
92
|
+
def self.format(obj)
|
93
|
+
# TODO: should formatter be overridable with a env var?
|
94
|
+
# formatter = begin config('FORMATTER'); rescue NameError => e; nil; end
|
95
|
+
# logger.debug "formatter: #{ formatter.inspect }"
|
96
|
+
if obj.rash_formatter
|
97
|
+
# there is some sort of formatting info
|
98
|
+
# even if the value is a string, we want to follow the instructions
|
99
|
+
# hell, maybe we want to write the string out as json or something :/
|
100
|
+
if obj.rash_formatter.respond_to? :call
|
101
|
+
# the value responds to `call`, so call it to get the value
|
102
|
+
# TODO: should we check that it returns a `String`?
|
103
|
+
obj.rash_formatter.call(obj)
|
104
|
+
# NOTE: `Object.singleton_methods` returns an array of strings in 1.8
|
105
|
+
# and an array of symbols in 1.9, so use strings to work in
|
106
|
+
# both.
|
107
|
+
elsif NRSER::Rash::Formatters.
|
108
|
+
singleton_methods.
|
109
|
+
map {|_| _.to_s }.
|
110
|
+
include? obj.rash_formatter.to_s
|
111
|
+
# it's a symbol that identifies on of the {NRSER::Rash::Formatters}
|
112
|
+
# class methods, so call that
|
113
|
+
NRSER::Rash::Formatters.send obj.rash_formatter, obj
|
114
|
+
else
|
115
|
+
# whatever, call the default
|
116
|
+
NRSER::Rash::Formatters.send config('DEFAULT_FORMATTER'), obj
|
117
|
+
end
|
118
|
+
else
|
119
|
+
# there is no formatting info
|
120
|
+
if obj.is_a? String
|
121
|
+
# in the case that a method passed back a `String`, i think we should
|
122
|
+
# consider it formatted and just print it
|
123
|
+
obj
|
124
|
+
elsif obj.nil?
|
125
|
+
# the result is nil and there has been no attempt to format it in
|
126
|
+
# a specific way that some program might need to recongize or
|
127
|
+
# something. at this point, i'm going to say that the function
|
128
|
+
# took some successful action and doesn't have anyhting to say about
|
129
|
+
# it, which i think means we shouldn't print anything
|
130
|
+
else
|
131
|
+
# otherwise, send it to the default formatter
|
132
|
+
NRSER::Rash::Formatters.send config('DEFAULT_FORMATTER'), obj
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end # module NRSER::Rash::CLI
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
using NRSER
|
8
|
+
using NRSER::Types
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
module NRSER::Rash::CLI
|
15
|
+
|
16
|
+
def self.help
|
17
|
+
# TODO: woefully incomplete
|
18
|
+
puts <<~EOF
|
19
|
+
Usage: rash COMMAND [ARGS...]
|
20
|
+
|
21
|
+
Commands:
|
22
|
+
list List functions you can call.
|
23
|
+
call Call a method from NRSER::Rash::Functions.
|
24
|
+
test Run tests for a method from NRSER::Rash::Functions.
|
25
|
+
help This message.
|
26
|
+
EOF
|
27
|
+
end
|
28
|
+
|
29
|
+
end # module NRSER::Rash::CLI
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Deps
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
# Project / Package
|
14
|
+
# -----------------------------------------------------------------------
|
15
|
+
|
16
|
+
|
17
|
+
# Refinements
|
18
|
+
# =======================================================================
|
19
|
+
|
20
|
+
|
21
|
+
# Declarations
|
22
|
+
# =======================================================================
|
23
|
+
|
24
|
+
|
25
|
+
# Definitions
|
26
|
+
# =======================================================================
|
27
|
+
|
28
|
+
module NRSER::Rash::CLI
|
29
|
+
|
30
|
+
# List the Rash functions available.
|
31
|
+
def self.list
|
32
|
+
NRSER::Rash.load_functions
|
33
|
+
puts NRSER::Rash.function_names
|
34
|
+
end
|
35
|
+
|
36
|
+
end # module NRSER::Rash
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
using NRSER
|
8
|
+
using NRSER::Types
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
module NRSER::Rash::CLI
|
15
|
+
|
16
|
+
# start here.
|
17
|
+
#
|
18
|
+
# this is the entry point for the script when executed. it expects a
|
19
|
+
# command as the first argument and dispatches to the associated method.
|
20
|
+
def self.run
|
21
|
+
SemanticLogger.add_appender io: $stderr, formatter: {
|
22
|
+
color: {
|
23
|
+
ap: {multiline: true},
|
24
|
+
}
|
25
|
+
}
|
26
|
+
SemanticLogger.default_level = NRSER::Rash.config( 'LOG_LEVEL' ).to_sym
|
27
|
+
|
28
|
+
# the command is the first argument
|
29
|
+
# we won't need or want it after this, so delete it
|
30
|
+
command = ARGV.shift
|
31
|
+
# filter out the command line config options
|
32
|
+
NRSER::Rash.filter_and_set_config ARGV
|
33
|
+
case command
|
34
|
+
when 'call'
|
35
|
+
# we are being asked to call a function. the name of the function is
|
36
|
+
# the second argument (now at index 0 since we deleted the command)
|
37
|
+
# and the rest of the arguments are passed to the function
|
38
|
+
call ARGV[0], ARGV[1..-1]
|
39
|
+
when 'test'
|
40
|
+
NRSER::Rash._test_function ARGV.shift #, ARGV[1, ARGV.length]
|
41
|
+
when 'list'
|
42
|
+
list
|
43
|
+
when 'help', '-h', '--help', nil
|
44
|
+
help
|
45
|
+
# Exit with error so these calls don't work with `&&` in shell
|
46
|
+
exit 1
|
47
|
+
when '--version', 'version', '-v'
|
48
|
+
puts NRSER::Rash::VERSION
|
49
|
+
else
|
50
|
+
call command, ARGV
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end # module NRSER::Rash::CLI
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Definitions
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Where the CLI commands live as class methods.
|
8
|
+
#
|
9
|
+
module NRSER::Rash::CLI
|
10
|
+
|
11
|
+
include SemanticLogger::Loggable
|
12
|
+
|
13
|
+
end # module NRSER::Rash::CLI
|
14
|
+
|
15
|
+
|
16
|
+
# Post-Processing
|
17
|
+
# =======================================================================
|
18
|
+
require_relative './cli/call'
|
19
|
+
require_relative './cli/help'
|
20
|
+
require_relative './cli/list'
|
21
|
+
require_relative './cli/run'
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Deps
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
# Project / Package
|
14
|
+
# -----------------------------------------------------------------------
|
15
|
+
|
16
|
+
|
17
|
+
# Refinements
|
18
|
+
# =======================================================================
|
19
|
+
|
20
|
+
using NRSER
|
21
|
+
using NRSER::Types
|
22
|
+
|
23
|
+
|
24
|
+
# Definitions
|
25
|
+
# =======================================================================
|
26
|
+
|
27
|
+
# @todo document NRSER::Rash module.
|
28
|
+
module NRSER::Rash
|
29
|
+
|
30
|
+
COMMAND_LINE_CONFIG = {}
|
31
|
+
|
32
|
+
|
33
|
+
# Get a config value by name. First looks for an env var defined with
|
34
|
+
# an added `'RASH_'` prefix, then for a const in the {NRSER::Rash}
|
35
|
+
# module with the provided name.
|
36
|
+
#
|
37
|
+
# @todo This example is out of date...
|
38
|
+
#
|
39
|
+
# Easiest to explain by example:
|
40
|
+
#
|
41
|
+
# NRSER::Rash::config('BLAH')
|
42
|
+
#
|
43
|
+
# will first see if there is an env var named
|
44
|
+
#
|
45
|
+
# 'RASH_BLAH'
|
46
|
+
#
|
47
|
+
# defined, and return it's value if so.
|
48
|
+
#
|
49
|
+
# Otherwise, it will try and return
|
50
|
+
#
|
51
|
+
# NRSER::RASH::Config::BLAH
|
52
|
+
#
|
53
|
+
# raising an exception if it's not found.
|
54
|
+
#
|
55
|
+
# Defined here so it can be used when defining the
|
56
|
+
# `NRSER::Rash::Config::<name>` consts.
|
57
|
+
#
|
58
|
+
def self.config name, *default
|
59
|
+
if default.length > 1
|
60
|
+
raise ArgumentError,
|
61
|
+
"wrong number of arguments" \
|
62
|
+
"(given #{ 1 + default.length }, expected 1-2)"
|
63
|
+
end
|
64
|
+
|
65
|
+
# command line config options take precedent (those that start with
|
66
|
+
# '--RASH_', which are never passed to the function)
|
67
|
+
if COMMAND_LINE_CONFIG.key? name
|
68
|
+
COMMAND_LINE_CONFIG[name]
|
69
|
+
elsif ENV.key? "RASH_#{ name }"
|
70
|
+
ENV["RASH_#{ name }"]
|
71
|
+
else
|
72
|
+
begin
|
73
|
+
Config.const_get(name)
|
74
|
+
rescue NameError => e
|
75
|
+
if default.empty?
|
76
|
+
raise
|
77
|
+
else
|
78
|
+
default[0]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
# Where the default config options are set.
|
86
|
+
#
|
87
|
+
# These are overridden by:
|
88
|
+
#
|
89
|
+
# 1. By command line options of the form
|
90
|
+
#
|
91
|
+
# --RASH_<name>
|
92
|
+
#
|
93
|
+
# where `<name>` corresponds to the `NRSER::Rash::Config::<name>`
|
94
|
+
# constant.
|
95
|
+
#
|
96
|
+
# 2. By environment variables of the form
|
97
|
+
#
|
98
|
+
# RASH_<name>
|
99
|
+
#
|
100
|
+
# where `<name>` corresponds to the `NRSER::Rash::Config.<name>`
|
101
|
+
# constant.
|
102
|
+
#
|
103
|
+
# Don't access these directly, use {NRSER::Rash.config} to access in
|
104
|
+
# proper precedence.
|
105
|
+
#
|
106
|
+
module Config
|
107
|
+
# Where to look for Rash files
|
108
|
+
HOME = ENV['HOME']
|
109
|
+
|
110
|
+
# Where to look for the Rash profile file
|
111
|
+
PROFILE = "#{ NRSER::Rash.config('HOME') }/profile.rb"
|
112
|
+
|
113
|
+
# Where to look for the Rash functions file
|
114
|
+
FUNCTIONS = "#{ NRSER::Rash.config('HOME') }/functions.rb"
|
115
|
+
|
116
|
+
# The default {NRSER::Rash::Formatter} to use
|
117
|
+
DEFAULT_FORMATTER = 'pp'
|
118
|
+
|
119
|
+
# Logging level
|
120
|
+
LOG_LEVEL = :info
|
121
|
+
|
122
|
+
# Print stacktrace on top-level function error
|
123
|
+
STACKTRACE = 'false'
|
124
|
+
|
125
|
+
# Don't print errors
|
126
|
+
PRINT_ERRORS = 'true'
|
127
|
+
|
128
|
+
# Stub function namespace separator
|
129
|
+
STUB_NAMESPACE_SEPERATOR = '__'
|
130
|
+
end
|
131
|
+
|
132
|
+
# Rash's project dir
|
133
|
+
ROOT_DIR = File.expand_path(File.dirname(__FILE__) + '/..')
|
134
|
+
|
135
|
+
# Executable
|
136
|
+
EXECUTABLE = ROOT_DIR + '/bin/rash'
|
137
|
+
|
138
|
+
# Proxy to {NRSER.truthy?}
|
139
|
+
#
|
140
|
+
def self.truthy? string
|
141
|
+
NRSER.truthy? string
|
142
|
+
end
|
143
|
+
|
144
|
+
# Old name without `?`
|
145
|
+
singleton_class.send :alias_method, :truthy, :truthy?
|
146
|
+
|
147
|
+
|
148
|
+
# Proxy to {NRSER.falsy?}
|
149
|
+
#
|
150
|
+
def self.falsy? string
|
151
|
+
return string.falsy?
|
152
|
+
end
|
153
|
+
|
154
|
+
# Old name
|
155
|
+
singleton_class.send :alias_method, :falsey, :falsy?
|
156
|
+
|
157
|
+
|
158
|
+
def self.filter_and_set_config(args)
|
159
|
+
args.reject! do |arg|
|
160
|
+
# long options of form '--<name>=<value>'
|
161
|
+
if m = arg.match(/\A--RASH_([^=]*)(=?)(.*)/)
|
162
|
+
COMMAND_LINE_CONFIG[m[1]] = if m[2] == ''
|
163
|
+
true
|
164
|
+
else
|
165
|
+
m[3]
|
166
|
+
end
|
167
|
+
true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
end # module NRSER::Rash
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Object
|
2
|
+
# Monkey-patch to add an instance variable named `rash_formatter`
|
3
|
+
# to `Object` to control how that object is formatted for printing if
|
4
|
+
# it's the final value returned to {NRSER::Rash::CLI.call}.
|
5
|
+
#
|
6
|
+
# The value should either be a symbol identifying a method on
|
7
|
+
# {NRSER::Rash::Formatters} to call or a callable that takes the object
|
8
|
+
# as it's only argument and returns a formatted `String`.
|
9
|
+
#
|
10
|
+
attr_accessor :rash_formatter
|
11
|
+
|
12
|
+
# shortcut method to set the `rash_formatter` and return the object.
|
13
|
+
# this method is hacked up a bit to support the following syntax:
|
14
|
+
#
|
15
|
+
# {:x => 1, :y => 2}.rash_formatter_tap :json
|
16
|
+
#
|
17
|
+
# {:x => 1, :y => 2}.rash_formatter_tap do |obj|
|
18
|
+
# "here's the object: #{ obj.inspect }"
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# which returns the object itself, allowing it to easily be tacked on to
|
22
|
+
# the last statement in a method. it's equivalent to:
|
23
|
+
#
|
24
|
+
# {:x => 1, :y => 2}.tap {|obj| obj.rash_formatter = :json}
|
25
|
+
#
|
26
|
+
# {:x => 1, :y => 2}.tap do |obj|
|
27
|
+
# obj.rash_formatter = Proc.new do |obj|
|
28
|
+
# "here's the object: #{ obj.inpsect }"
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
def rash_formatter_tap(formatter = (default = true; nil), &block)
|
33
|
+
if default
|
34
|
+
if block.nil?
|
35
|
+
# neither the `formatter` arg or a block were supplied, so
|
36
|
+
# the method is acting as an attribute reader, return the
|
37
|
+
# value
|
38
|
+
raise ArgumentError.new "must provide an argument or block."
|
39
|
+
else
|
40
|
+
# only a block was supplied, set it as the formatter and
|
41
|
+
# return the object
|
42
|
+
@rash_formatter = block
|
43
|
+
self
|
44
|
+
end
|
45
|
+
else
|
46
|
+
if block
|
47
|
+
raise ArgumentError.new "can't provide an argument and block."
|
48
|
+
else
|
49
|
+
# only `formatter` arg was supplied, set it and return the object
|
50
|
+
@rash_formatter = formatter
|
51
|
+
self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end # class Object
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
using NRSER
|
8
|
+
using NRSER::Types
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
# these are functions mapping an `Object` to a `String` for printing.
|
15
|
+
# their names can be used as values for `Object.rash_formatter` to indicate
|
16
|
+
# Rash should use that function to print the object.
|
17
|
+
#
|
18
|
+
module NRSER::Rash::Formatters
|
19
|
+
def self.yaml(obj)
|
20
|
+
require 'yaml'
|
21
|
+
YAML.dump(obj)
|
22
|
+
end
|
23
|
+
|
24
|
+
# print a white-space formatted key/value table given a hash.
|
25
|
+
# keys and values are printed cast to strings, and nested
|
26
|
+
# hashes are treated as sub-keys:
|
27
|
+
#
|
28
|
+
# NRSER::Rash::Formatters.kv({
|
29
|
+
# :scheme => "https",
|
30
|
+
# :host => "www.google.com",
|
31
|
+
# :port => 443,
|
32
|
+
# :params => {
|
33
|
+
# :q => "blah",
|
34
|
+
# :oq => "blah",
|
35
|
+
# :aqs => "chrome.0.57j60l4j59.468",
|
36
|
+
# :sourceid => "chrome",
|
37
|
+
# :ie => "UTF-8"
|
38
|
+
# },
|
39
|
+
# :fragment => nil
|
40
|
+
# })
|
41
|
+
#
|
42
|
+
# scheme: https
|
43
|
+
# host: www.google.com
|
44
|
+
# port: 443
|
45
|
+
# params:
|
46
|
+
# q: blah
|
47
|
+
# oq: blah
|
48
|
+
# aqs: chrome.0.57j60l4j59.468
|
49
|
+
# sourceid: chrome
|
50
|
+
# ie: UTF-8
|
51
|
+
# fragment:
|
52
|
+
#
|
53
|
+
def self.kv(hash)
|
54
|
+
find_width = lambda do |hash, indent|
|
55
|
+
width = 0
|
56
|
+
hash.each do |key, value|
|
57
|
+
this_width = if value.is_a? Hash
|
58
|
+
find_width.call(value, indent + 2)
|
59
|
+
else
|
60
|
+
key.to_s.length + indent
|
61
|
+
end
|
62
|
+
if this_width > width
|
63
|
+
width = this_width
|
64
|
+
end
|
65
|
+
end
|
66
|
+
width
|
67
|
+
end
|
68
|
+
width = find_width.call(hash, 0)
|
69
|
+
out = ''
|
70
|
+
write_out = lambda do |hash, indent|
|
71
|
+
hash.each do |key, value|
|
72
|
+
out << ' ' * indent \
|
73
|
+
<< "#{ key }: " \
|
74
|
+
<< ' ' * (width - key.to_s.length - indent)
|
75
|
+
if value.is_a? Hash
|
76
|
+
out << "\n"
|
77
|
+
write_out.call(value, indent + 2)
|
78
|
+
else
|
79
|
+
out << "#{ value }\n"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
write_out.call(hash, 0)
|
84
|
+
out
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.json(obj)
|
88
|
+
require 'json'
|
89
|
+
JSON.dump(obj)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.json_pp(obj)
|
93
|
+
require 'json'
|
94
|
+
JSON.pretty_generate(obj)
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.pp(obj)
|
98
|
+
require 'pp'
|
99
|
+
require 'stringio'
|
100
|
+
sio = StringIO.new
|
101
|
+
PP.pp(obj, sio)
|
102
|
+
sio.string
|
103
|
+
end
|
104
|
+
|
105
|
+
end # module NRSER::Rash::Formatters
|