console_utils 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e5dbc7f627c5c02f9c9075f44a1146e7d35e2039
4
+ data.tar.gz: ecc4433de0aaebbf0b7a3bae68939a1773cb8ac5
5
+ SHA512:
6
+ metadata.gz: 2fd7b962b54208e49932a4e9ff4caf4005443a10562bc8cac0efab42cabad1d766e2b032f469e39d3d9a22f3d14a066566c1bc4df3486c432d14fe8aa9284332
7
+ data.tar.gz: fb9aeb8c86251d0abac713e2e0a61cd103fb6aa2590556eb65200a6f52df6e13badf72f635cd982407915a06089dee0e728e6918c5239554479b4b11aecc29d3
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.tm_properties
2
+ /.rake_t_cache
3
+ /.bundle/
4
+ /.yardoc
5
+ /Gemfile.lock
6
+ /_yardoc/
7
+ /coverage/
8
+ /doc/
9
+ /pkg/
10
+ /spec/reports/
11
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rails-console-utils.gemspec
4
+ gemspec
5
+
6
+ gem "rails", "~> 4.2"
7
+ gem "pry"
8
+ gem "rspec"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Anton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,238 @@
1
+ # Rails Console Utils
2
+
3
+ ConsoleUtils gem provides several handy tools to use in Rails Console. It includes following modules:
4
+
5
+ 1. **[RequestUtils](#requestutils)**
6
+ the collection of methods to make either local or remote JSON API requests.
7
+ Provides response body formatting and auto-token authentication feature
8
+ (currently supports only params tokens).
9
+ 2. **[BenchUtils](#benchutils)**
10
+ benchmark shorthands
11
+ 3. **[ActiveRecordUtils](#activerecordutils)**
12
+ useful console methods for ActiveRecord::Base models
13
+ 4. **[OtherUtils](#otherutils)**
14
+ uncategorized methods
15
+
16
+ The gem was collected from several **very *(very-very)* raw** modules used in different projects in different time. The code was refactored, but currently there are no specs or complete docs (sowwy ^_^), but they are *coming soon*.
17
+
18
+ ## Installation
19
+
20
+ Add this lines to your application's Gemfile.
21
+ **Note**: when using with `pry-rails` gem, make sure to depend it before this gem.
22
+
23
+ ```ruby
24
+ group :development do
25
+ \## to enable inspecting procs' sources, uncomment next lines:
26
+ \# gem 'term-ansicolor', '1.1.5'
27
+ \# gem 'sourcify', '~> 0.6.0.rc4', require: false
28
+
29
+ \## when using `pry-rails`, it should be somewhere here:
30
+ # gem 'pry-rails'
31
+
32
+ gem 'console_utils'
33
+ end
34
+ ```
35
+
36
+ And then execute:
37
+
38
+ $ bundle
39
+
40
+ ## Configuration
41
+
42
+ Parameters are changable by the `config.console_utils` key inside the app's configuration block. It is also available as `ConsoleUtils.configure(&block)` in the custom initializer file.
43
+
44
+ Example part of `config/environments/development.rb`:
45
+
46
+ ```ruby
47
+ Rails.application.configure do
48
+ # ...
49
+ if config.console_utils
50
+ config.console_utils.json_formatter = :jq
51
+ config.console_utils.remote_endpoint = Settings.base_url
52
+ end
53
+ end
54
+ ```
55
+
56
+ ### Options:
57
+
58
+ * `auto_token` - Enable auto-fetch of user's auth token in requests (default: `true`)
59
+ * `curl_bin` - Binary path to curl (using in remote requests). (default: `"curl"`)
60
+ * `curl_silence` - Disable print out generated curl command with remote requests. (default: `false`)
61
+ * `default_uid` - ID of the user which will be used by default in requests (default: `1`)
62
+ * `disabled_modules` - An array of disabled modules' names (default: `[]`)
63
+ * `jq_command` - Command for jq json formatter (default: `"jq . -C"`)
64
+ * `json_formatter` - JSON formatter used in API request helpers (:default or :jq)
65
+ * `logger` - Output logger (Rails.logger by default)
66
+ * `remote_endpoint` - Remote endpoint used in remote API request helpers (default: `"http://example.com"`)
67
+ * `token_param` - A name of the request parameter used to authorize user by a token (default: `:token`)
68
+ * `user_model_name` - A name of user's model (default: `:User`)
69
+ * `user_primary_key` - A primary key of user's model (default: `:id`)
70
+ * `user_token_column` - A column name with a user's token. Using by request tools. (default: `:auth_token`)
71
+
72
+ ## RequestUtils
73
+
74
+ Includes requesters to a local (`exap`) or a remote (`remo`) project's API. There are many customizable settings in configuration, so it's better to check them before playing with this feature.
75
+
76
+ The following examples are actual to both of requesters - just swap `exap` to `remo` and it will work.
77
+
78
+ Appends auth token of default user to params, makes request and prints formatted response:
79
+
80
+ ```ruby
81
+ exap.get("api/posts.json").preview
82
+ ```
83
+
84
+ Authorize user #42, also copy formatted response to the pasteboard:
85
+
86
+ ```ruby
87
+ exap.get("api/posts.json", 42).preview(&:pbcopy)
88
+ ```
89
+
90
+ Authorize random user:
91
+
92
+ ```ruby
93
+ exap.get("api/comments.json", :any).preview
94
+ ```
95
+
96
+ Use additional request params (skip the second parameter to use default user), don't print response body:
97
+
98
+ ```ruby
99
+ exap.put("api/account.json", 42, user: { name: "Anton" })
100
+ ```
101
+
102
+ Skip auto-fetching user's token:
103
+
104
+ ```ruby
105
+ exap.post("api/signup.json", nil, user: { name: "Guest" }).preview
106
+ ```
107
+
108
+ **Note:** The `remo` requester supports the auto-token feature, but still fetchs tokens from a local DB.
109
+
110
+ ## BetchUtils
111
+
112
+ Access to globally shared Benchmark.ips object, which works out of a block and allows to change the stack “on the fly” and to keep the result during the work.
113
+
114
+ Just add reports:
115
+
116
+ ```ruby
117
+ chips.("merge") { the_hash.merge(other_hash) }
118
+ chips.("merge!") { the_hash.merge!(other_hash) }
119
+ \# => x.report(..) { ... }
120
+ ```
121
+
122
+ ... and compare!
123
+
124
+ ```ruby
125
+ chips.compare! # compares two reports: "merge" and "merge!"
126
+ ```
127
+
128
+ And add more reports after:
129
+
130
+ ```ruby
131
+ chips.("deep_merge") { the_hash.deep_merge(other_hash) }
132
+ ```
133
+
134
+ ... or change the existing one:
135
+
136
+ ```ruby
137
+ chips.("merge!") { the_hash.deep_merge!(other_hash) }
138
+ ```
139
+
140
+ ... and compare again!
141
+
142
+ ```ruby
143
+ chips.compare! # compare three reports: "merge", changed "merge!" and new "deep_merge"
144
+ ```
145
+
146
+ You can remove report by a label:
147
+
148
+ ```ruby
149
+ chips.del("merge!")
150
+ ```
151
+
152
+ Split to a separate `Chips` object:
153
+
154
+ ```ruby
155
+ other_chips = chips.split!("deep_merge") # split reports to separate hash
156
+ ```
157
+
158
+ Well, to be honest, it is just a delegator of a reports hash, so:
159
+
160
+ ```ruby
161
+ chips # => { "merge" => proc { ... }, ... }
162
+ chips["merge"] # => proc { ... }
163
+ chips.clear # clear all reports
164
+ ```
165
+
166
+ ## ActiveRecordUtils
167
+
168
+ Includes methods to query a random record:
169
+
170
+ ```ruby
171
+ User.random # => reorder("RANDOM()")
172
+ User.anyone # get a random record (like [].sample method)
173
+ User.active.anyone # works under a scope - get a random active record
174
+ User.anyid # get random id of an existing record
175
+ ```
176
+
177
+ Also provides shorthand to find any user by id: `usr(id)`
178
+
179
+ ## OtherUtils
180
+
181
+ #### clr()
182
+ Term::ANSIColor shorthand
183
+
184
+ #### shutting(:engine_key[, to: logger_level]) {}
185
+ Shuts up the logger of a specified Rails engine for a given key (`:rails`, `:record`, `:controller` or `:view`).
186
+
187
+ ```ruby
188
+ shutting(:view, to: :warn) do
189
+ ActionView.logger.info("not printed")
190
+ ActionView.logger.warn("printed")
191
+ Rails.logger.info("printed")
192
+ end
193
+
194
+ shutting(:rails, to: Logger::INFO) { ... }
195
+ shutting(:record, to: 1) { ... }
196
+ ```
197
+
198
+ ## Array#to_proc
199
+
200
+ > Oh no, core class extension!
201
+
202
+ Converts array to proc with chained calls of items. Every item can be either a method name or an array containing a method name and args.
203
+
204
+ ```ruby
205
+ the_hash = { :one => "One", :two => "Two", :three => 3, :four => nil }
206
+ the_hash.select(&[[:[], 1], [:is_a?, String]])
207
+ \# => { :one => "One", :two => "Two" }
208
+ ```
209
+
210
+ Pretty good, huh? ;)
211
+
212
+ See again:
213
+
214
+ ```ruby
215
+ mapping = { "one" => "1", "two" => "2", "" => "0" }
216
+ the_hash.values.map(&[:to_s, :downcase, [:sub, /one|two|$^/, mapping]])
217
+ \# => ["1", "2", "3", "0"]
218
+ ```
219
+
220
+ Avoid to use it in production, seriously.
221
+
222
+ ## AwesomePrint::Proc
223
+
224
+ Just prints proc's source when inspecting proc. `Sourcify` is required, see the **Installation** section for notes.
225
+
226
+ ## Development
227
+
228
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
229
+
230
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
231
+
232
+ ## Contributing
233
+
234
+ 1. Fork it ( https://github.com/[my-github-username]/console_utils/fork )
235
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
236
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
237
+ 4. Push to the branch (`git push origin my-new-feature`)
238
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rdoc/task'
4
+
5
+ RDoc::Task.new do |rdoc|
6
+ rdoc.main = "README.md"
7
+ rdoc.rdoc_dir = "doc"
8
+ rdoc.rdoc_files.include("README.md", "lib/**/*.rb")
9
+ rdoc.options = ["--no-dcov", "--visibility=protected"]
10
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "console_utils"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ Pry.start
12
+
13
+ # require "irb"
14
+ # IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'console_utils/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "console_utils"
8
+ spec.version = ConsoleUtils::VERSION
9
+ spec.authors = ["Anton"]
10
+ spec.email = ["anton.estum@gmail.com"]
11
+
12
+ spec.summary = %q{Groovy tools for Rails Console.}
13
+ spec.description = %q{Console Utils provides several handy tools to use in Rails Console.}
14
+ spec.homepage = "https://github.com/estum/console_utils"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "rails", ">= 4.1", "< 5"
21
+ spec.add_dependency "term-ansicolor"
22
+ spec.add_dependency "awesome_print"
23
+ spec.add_dependency "benchmark-ips"
24
+ # spec.add_dependency 'sourcify', '~> 0.6.0.rc4'
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.9"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rdoc"
29
+ end
@@ -0,0 +1,42 @@
1
+ #:nodoc: all
2
+
3
+ begin
4
+ require "sourcify"
5
+ rescue LoadError
6
+ end
7
+
8
+ module AwesomePrint
9
+ module Proc
10
+ #:startdoc:
11
+ def self.included(base)
12
+ base.send :alias_method, :cast_without_proc, :cast
13
+ base.send :alias_method, :cast, :cast_with_proc
14
+ end
15
+
16
+ # Add Proc class to the dispatcher pipeline.
17
+ def cast_with_proc(obj, type)
18
+ if (type == :proc || obj.is_a?(::Proc)) && obj.respond_to?(:to_source)
19
+ :proc
20
+ else
21
+ cast_without_proc(obj, type)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ # Format Proc object.
28
+ def awesome_proc(obj)
29
+ if !@options[:raw] && (/\A(?<kw>proc)\s*(?<block_source>.+?)\z/ =~ obj.to_source)
30
+ kw = "->" if obj.lambda?
31
+ sprintf("%s %s", colorize(kw, :keyword), colorize(block_source, :string))
32
+ else
33
+ awesome_object(obj)
34
+ end
35
+ end
36
+ #:enddoc:
37
+ end
38
+ end
39
+
40
+ if defined?(Sourcify) && Sourcify::VERSION >= "0.6.0.rc4"
41
+ AwesomePrint::Formatter.include(AwesomePrint::Proc)
42
+ end
@@ -0,0 +1,164 @@
1
+ require "active_support"
2
+ require "active_support/rails"
3
+ require 'term/ansicolor'
4
+ require 'console_utils/core_ext/array_to_proc'
5
+ require "console_utils/version"
6
+
7
+ begin
8
+ require "awesome_print"
9
+ rescue LoadError
10
+ end
11
+
12
+ require "awesome_print/proc" if defined?(AwesomePrint)
13
+
14
+ # = Rails Console Utils
15
+ # Collection of utilities to use in Rails Console.
16
+ #
17
+ # == Modules
18
+ #
19
+ # [ActiveRecordUtils]
20
+ #
21
+ # useful console methods for <tt>ActiveRecord::Base</tt> models
22
+ #
23
+ # [BenchUtils]
24
+ #
25
+ # benchmark shorthands
26
+ #
27
+ # [RequestUtils]
28
+ #
29
+ # tools to make local and remote JSON API requests with
30
+ # json response body formatting and automatic auth
31
+ # (currently supports only token auth).
32
+ #
33
+ # [OtherUtils]
34
+ #
35
+ # uncategorized collection of methods
36
+ #
37
+ # == Configuration
38
+ # Parameters are changable by the <tt>config.console_utils</tt> key inside
39
+ # the app's configuration block. It is also available as
40
+ # <tt>ConsoleUtils.configure(&block)</tt> in the custom initializer.
41
+ module ConsoleUtils
42
+ extend ActiveSupport::Autoload
43
+
44
+ MODULES = [
45
+ :ActiveRecordUtils,
46
+ :RequestUtils,
47
+ :BenchUtils,
48
+ :OtherUtils
49
+ ]
50
+
51
+ MODULES.each { |mod| autoload mod }
52
+
53
+ JSON_FORMATTERS = %i(default jq)
54
+
55
+ # :section: Configuration
56
+
57
+ ##
58
+ # :attr:
59
+ # An array with disabled modules (default: <tt>[]</tt>)
60
+ mattr_accessor(:disabled_modules) { [] }
61
+ ##
62
+ # :attr:
63
+ # Enable the auto-fetching of user's auth token in requests
64
+ # (default: <tt>true</tt>)
65
+ mattr_accessor(:auto_token) { true }
66
+ ##
67
+ # :attr:
68
+ # ID of the user which will be used by default in requests
69
+ # (default: <tt>1</tt>)
70
+ mattr_accessor(:default_uid) { 1 }
71
+ ##
72
+ # :attr:
73
+ # A name of user's model (default: <tt>:User</tt>)
74
+ mattr_accessor(:user_model_name) { :User }
75
+ ##
76
+ # :attr:
77
+ # A primary key of user's model (default: <tt>:id</tt>)
78
+ mattr_accessor(:user_primary_key) { :id }
79
+ ##
80
+ # :attr:
81
+ # A column name with a user's token. Using by request tools.
82
+ # (default: <tt>:auth_token</tt>)
83
+ mattr_accessor(:user_token_column) { :auth_token }
84
+ ##
85
+ # :attr:
86
+ # A name of the request parameter used to authorize user by a token
87
+ # (default: <tt>:token</tt>)
88
+ mattr_accessor(:token_param) { :token }
89
+ ##
90
+ # :attr:
91
+ # JSON formatter used in API request helpers
92
+ # (<tt>:default</tt> or <tt>:jq</tt>)
93
+ mattr_accessor(:json_formatter) { :default }
94
+ ##
95
+ # :attr:
96
+ # Command for +jq+ json formatter (default: <tt>"jq . -C"</tt>)
97
+ mattr_accessor(:jq_command) { "jq . -C" }
98
+ ##
99
+ # :attr:
100
+ # Binary path to +curl+ (using in remote requests). (default: <tt>"curl"</tt>)
101
+ mattr_accessor(:curl_bin) { "curl" }
102
+ ##
103
+ # :attr:
104
+ # Don't print generated curl command with remote requests.
105
+ # (default: <tt>false</tt>)
106
+ mattr_accessor(:curl_silence) { false }
107
+ ##
108
+ # :attr:
109
+ # Remote endpoint used in remote API request helpers
110
+ # (default: <tt>"http://example.com"</tt>)
111
+ mattr_accessor(:remote_endpoint) { "http://example.com" }
112
+ ##
113
+ # :attr:
114
+ # Output logger (<tt>Rails.logger</tt> by default)
115
+ mattr_accessor :logger
116
+
117
+
118
+ # :section: Class Methods
119
+
120
+ class << self
121
+ def config
122
+ self
123
+ end
124
+ private :config
125
+
126
+ # :method: self.configure
127
+ def configure
128
+ yield(config)
129
+ end
130
+
131
+ # Returns User's class set in the <tt>:user_class_name</tt>
132
+ def user_model
133
+ Object.const_get(user_model_name)
134
+ end
135
+ alias_method :user_class, :user_model
136
+
137
+ # Finds +user_model+ by +user_primary_key+
138
+ def find_user(id, scope: nil)
139
+ (scope || user_model).where(user_primary_key => id).first!
140
+ end
141
+
142
+ def enabled_modules
143
+ ConsoleUtils::MODULES - disabled_modules
144
+ end
145
+
146
+ # Yields each enabled module with a given block
147
+ def each_enabled_module
148
+ enabled_modules.each { |mod| yield const_get(mod) }
149
+ end
150
+
151
+ # Setup enabled modules by extending given context
152
+ def setup_modules_to(context = nil)
153
+ context = yield() if block_given?
154
+ puts "Console instance: #{context.inspect}" if ENV["CONSOLE_UTILS_DEBUG"]
155
+ each_enabled_module { |mod| context.send(:extend, mod) }
156
+ end
157
+ end
158
+
159
+ ActiveSupport.run_load_hooks(:console_utils, self)
160
+ end
161
+
162
+ if defined? Rails
163
+ require "console_utils/railtie"
164
+ end
@@ -0,0 +1,19 @@
1
+ module ConsoleUtils #:nodoc:
2
+ module ActiveRecordUtils
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :RandomRecord
6
+
7
+ def self.extended(mod)
8
+ ActiveSupport.on_load(:active_record) do
9
+ ActiveRecord::Relation.send(:include, RandomRecord::FinderMethods)
10
+ ActiveRecord::Base.send(:extend, RandomRecord::Querying)
11
+ end
12
+ end
13
+
14
+ # Shortcut to <tt>ConsoleUtils.find_user(id)</tt>
15
+ def usr(id)
16
+ ConsoleUtils.find_user(id)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module ConsoleUtils::ActiveRecordUtils #:nodoc:
2
+ module RandomRecord #:nodoc:
3
+ module FinderMethods
4
+ def random
5
+ reorder('RANDOM()')
6
+ end
7
+
8
+ def anyone
9
+ random.first
10
+ end
11
+
12
+ def anyid
13
+ anyone.id
14
+ end
15
+ end
16
+
17
+ module Querying
18
+ delegate :random, :anyone, :anyid, to: :all
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,46 @@
1
+ module ConsoleUtils #:nodoc:
2
+
3
+ # = Benchmark utils
4
+ #
5
+ # Provides the collection of tools for benchmarking
6
+
7
+ module BenchUtils
8
+ extend ActiveSupport::Autoload
9
+
10
+ autoload :Chips
11
+
12
+ # :call-seq:
13
+ # chips[ .("report") {} | .compare! {} | ... ]
14
+ #
15
+ # Access to globally shared <tt>Benchmark.ips</tt> object, which
16
+ # works out of a block and allows to change the stack "on the fly"
17
+ # and to keep the result during the work.
18
+ #
19
+ # ==== Examples
20
+ #
21
+ # chips.("merge") { the_hash.merge(other_hash) }
22
+ # chips.("merge!") { the_hash.merge!(other_hash) }
23
+ # # => x.report(..) { ... }
24
+ #
25
+ # chips.compare! # compare two reports
26
+ #
27
+ # # add more reports:
28
+ # chips.("deep_merge") { the_hash.deep_merge(other_hash) }
29
+ #
30
+ # # change an existing:
31
+ # chips.("merge!") { the_hash.deep_merge!(other_hash) }
32
+ #
33
+ # chips.compare! # compare three reports
34
+ #
35
+ # # remove report labeled as "merge!":
36
+ # chips.del("merge!")
37
+ #
38
+ # # it is just a delegator of the hash:
39
+ # chips # => { "merge" => #<Proc:...>, ... }
40
+ # chips["merge"] # => #<Proc:...>
41
+ # chips.clear # clear procs
42
+ def chips
43
+ Chips.shared
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ require "benchmark/ips"
2
+
3
+ module ConsoleUtils::BenchUtils #:nodoc:
4
+ class Chips < SimpleDelegator
5
+ class << self
6
+ # The globally shared +Chips+ object
7
+ def shared
8
+ @shared ||= new
9
+ end
10
+
11
+ def method_missing(meth, *args, &blk)
12
+ shared.respond_to?(meth) ? shared.send(meth, *args, &blk) : super
13
+ end
14
+
15
+ def respond_to_missing?(*args)
16
+ shared.respond_to?(*args) || super
17
+ end
18
+ end
19
+
20
+ attr_reader :results
21
+
22
+ # Creates Chips context using a given hash of reports.
23
+ def initialize(reports = nil)
24
+ super(reports.to_h)
25
+ @results = []
26
+ end
27
+
28
+ # Executes <tt>Benchmark.ips {|x| ...; x.compare! }</tt> using
29
+ # the given hash of procs as reports and push the result to
30
+ # <tt>results</tt> stack.
31
+ def compare!
32
+ results << begin
33
+ Benchmark.ips do |x|
34
+ each_pair {|name, proc| x.report(name, &proc) }
35
+ x.compare!
36
+ end
37
+ end
38
+ end
39
+
40
+ # :call-seq:
41
+ # call("label") { ...things to bench... }
42
+ #
43
+ # Adds a labeled report block. The same as <tt>x.report(label) { ... }</tt>.
44
+ def call(name, &block)
45
+ self[name] = block.to_proc
46
+ end
47
+
48
+ # Get a recent result
49
+ def recent
50
+ results.last
51
+ end
52
+
53
+ # Splits reports to a new context
54
+ def split!(*args)
55
+ Chips.new(__getobj__.split!(*args))
56
+ end
57
+
58
+ def del(*args)
59
+ __getobj__.delete(*args)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,30 @@
1
+ unless Array.method_defined?(:to_proc)
2
+ class Array
3
+ # :call-seq:
4
+ # [].to_proc
5
+ # &[chain, [:of_calls, and, args], ...]
6
+ #
7
+ # Converts array to proc with chained calls of items.
8
+ # Every item can be either a method name or an array containing
9
+ # a method name and args.
10
+ #
11
+ # ==== Examples
12
+ #
13
+ # the_hash = { :one => "One", :two => "Two", :three => 3, :four => nil }
14
+ # mapping = { "one" => "1", "two" => "2", "" => "0" }
15
+ #
16
+ # the_hash.select(&[[:[], 1], [:is_a?, String]])
17
+ # # => { :one => "One", :two => "Two" }
18
+ #
19
+ # the_hash.values.map(&[:to_s, :downcase, [:sub, /one|two|$^/, mapping]])
20
+ # # => ["1", "2", "3", "0"]
21
+ def to_proc
22
+ proc do |*obj|
23
+ obj = obj.shift if obj.size == 1
24
+ reduce(obj) do |chain, sym|
25
+ chain.public_send(*Array(sym).flatten)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,56 @@
1
+ module ConsoleUtils #:nodoc:
2
+ module OtherUtils
3
+ # <tt>Term::ANSIColor</tt> shorthand
4
+ def clr
5
+ Term::ANSIColor
6
+ end
7
+
8
+ # :call-seq:
9
+ # shutting(:engine_key[, to: logger_level]) {}
10
+ #
11
+ # Shuts up logger of Rails engine by a given key (<tt>:rails</tt>, <tt>:record</tt>,
12
+ # <tt>:controller</tt> or <tt>:view</tt>).
13
+ #
14
+ # shutting(:view, to: :warn) do
15
+ # ActionView.logger.info("not printed")
16
+ # ActionView.logger.warn("printed")
17
+ # Rails.logger.info("printed")
18
+ # end
19
+ #
20
+ # shutting(:rails, to: Logger::INFO) { ... }
21
+ # shutting(:record, to: 1) { ... }
22
+ #
23
+ def shutting(*args, &block)
24
+ Shutting.(*args, &block)
25
+ end
26
+
27
+ class Shutting
28
+ ENGINES_KEYS_MAP = {
29
+ :rails => "Rails",
30
+ :record => "ActiveRecord::Base",
31
+ :controller => "ActionController::Base",
32
+ :view => "ActionView::Base"
33
+ }
34
+
35
+ def self.call(*args, &block)
36
+ new(*args).call(&block)
37
+ end
38
+
39
+ def initialize(key, to: Logger::WARN)
40
+ @key = key
41
+ @level = to
42
+ @level = Logger.const_get(@level.upcase) unless @level.is_a?(Numeric)
43
+ end
44
+
45
+ def call(&block)
46
+ with_logger { |logger| logger.silence(@level, &block) }
47
+ end
48
+
49
+ # Yields engine's logger for a given key.
50
+ def with_logger
51
+ const_get(ENGINES_KEYS_MAP[@key]).
52
+ logger.tap { |logger| yield(logger) unless logger.nil? }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,35 @@
1
+ require "rails/railtie"
2
+
3
+ module ConsoleUtils
4
+ ##
5
+ # Console Utils Railtie
6
+ class Railtie < ::Rails::Railtie
7
+ #:nodoc: all
8
+ config.console_utils = ActiveSupport::OrderedOptions.new
9
+
10
+ initializer 'console_utils.logger' do
11
+ ActiveSupport.on_load(:console_utils) { self.logger = ::Rails.logger }
12
+ end
13
+
14
+ initializer "console_utils.set_configs" do |app|
15
+ options = app.config.console_utils
16
+
17
+ options.disabled_modules ||= ConsoleUtils.disabled_modules
18
+ options.disabled_modules << :ActiveRecordUtils unless defined?(ActiveRecord)
19
+
20
+ ActiveSupport.on_load(:console_utils) do
21
+ options.each { |k,v| send(:"#{k}=", v) }
22
+ end
23
+ end
24
+
25
+ console do |app|
26
+ ConsoleUtils.setup_modules_to do
27
+ if defined?(Pry)
28
+ TOPLEVEL_BINDING.eval('self')
29
+ else
30
+ Rails.application.config.console::ExtendCommandBundle
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,77 @@
1
+ module ConsoleUtils #:nodoc:
2
+
3
+ # = Request Utils
4
+ # Provides the collection of tools to make JSON API requests and get formatted output.
5
+ # To use system-installed +jq+ utility to format json, change +json_formatter+
6
+ # option in the config.
7
+
8
+ module RequestUtils
9
+ extend ActiveSupport::Autoload
10
+
11
+ autoload :Requester
12
+ autoload :Exap
13
+ autoload :Remo
14
+
15
+ # :call-seq:
16
+ # autoken(id)
17
+ # autoken(:any)
18
+ #
19
+ # Returns user's token by primary key. Use <tt>:any</tt> to get random user.
20
+ def autoken(id)
21
+ user = id == :any ? user_scope.anyone : ConsoleUtils.find_user(id, scope: user_scope)
22
+ puts "User #{user.public_send(ConsoleUtils.user_primary_key)}" if id == :any
23
+ user.public_send(ConsoleUtils.user_token_column)
24
+ end
25
+
26
+ # :call-seq:
27
+ # exap(.get|.post|.put|...)(url, user_id = nil, **params)
28
+ #
29
+ # Local API requester context.
30
+ # See also: <tt>ConsoleUtils::RequestUtils::Exap</tt>
31
+ #
32
+ # ==== Examples:
33
+ #
34
+ # Appends auth token of default user to params, makes request and prints formatted response:
35
+ #
36
+ # exap.get("api/posts.json").preview
37
+ #
38
+ # Authorize user #42, also copy formatted response to the pasteboard:
39
+ #
40
+ # exap.get("api/posts.json", 42).preview(&:pbcopy)
41
+ #
42
+ # Authorize random user:
43
+ #
44
+ # exap.get("api/comments.json", :any).preview
45
+ #
46
+ # Use additional request params (skip the second parameter to use default user),
47
+ # don't print response body:
48
+ #
49
+ # exap.put("api/account.json", 42, user: { name: "Anton" })
50
+ #
51
+ # Skip auto-fetching user's token:
52
+ #
53
+ # exap.post("api/signup.json", nil, user: { name: "Guest" }).preview
54
+
55
+ def exap
56
+ Exap.new(self)
57
+ end
58
+
59
+ # :call-seq:
60
+ # remo(.get|.post|.put|...)(url, user_id = nil, **params)
61
+ #
62
+ # Remote API requester context.
63
+ # See also: <tt>ConsoleUtils::RequestUtils::Remo</tt>
64
+ #
65
+ # ==== Examples:
66
+ # See +exap+ examples.
67
+ def remo
68
+ Remo.new(self)
69
+ end
70
+
71
+ private
72
+
73
+ def user_scope
74
+ ConsoleUtils.user_model.select([:id, :auth_token])
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,31 @@
1
+ require "console_utils/request_utils/requester"
2
+
3
+ module ConsoleUtils::RequestUtils #:nodoc:
4
+ class Exap < Requester
5
+ INSPECT_FORMAT = "<Local: %s (%s)>".freeze
6
+
7
+ REQUEST_METHODS.each do |reqm|
8
+ define_method(reqm) { |*args| resp_wrap(reqm, *args) }
9
+ end
10
+
11
+ def to_s
12
+ response.try(:body)
13
+ end
14
+
15
+ def inspect
16
+ format INSPECT_FORMAT, request.path, response.status
17
+ end
18
+
19
+ private
20
+
21
+ delegate :controller, to: :app, prefix: true, allow_nil: true
22
+ delegate :request, :response, to: :app_controller, allow_nil: true
23
+
24
+ def resp_wrap(meth, url, *args)
25
+ @url, @_args = url, args
26
+ p args
27
+ app.send(meth, url, *normalize_args)
28
+ self
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,59 @@
1
+ require 'uri'
2
+ require "console_utils/request_utils/requester"
3
+
4
+ module ConsoleUtils::RequestUtils #:nodoc:
5
+ class Remo < Requester
6
+ OUT_FORMAT = "\n%{size_download}\n%{time_total}".freeze
7
+ INSPECT_FORMAT = "<Remote: %s in %s ms>".freeze
8
+ INSPECT_NOTHING = "<Remote: nothing>".freeze
9
+
10
+ attr_reader :request_method
11
+
12
+ REQUEST_METHODS.each do |reqm|
13
+ define_method(reqm) do |url, *args|
14
+ @_args = args
15
+ @url = urlify(url, *normalize_args)
16
+ @request_method = reqm.to_s.upcase
17
+ perform
18
+ end
19
+ end
20
+
21
+ def inspect
22
+ if @url && @_time
23
+ format(INSPECT_FORMAT, @url, @_time)
24
+ else
25
+ INSPECT_NOTHING
26
+ end
27
+ end
28
+
29
+ def to_s
30
+ @_body
31
+ end
32
+
33
+ protected
34
+
35
+ def perform
36
+ IO.popen(curl_command, "r+") { |io| set_payload!(io.readlines) }
37
+ end
38
+
39
+ private
40
+
41
+ def set_payload!((*body_lines, size, time))
42
+ @_body = body_lines.join
43
+ @_size = size.to_f
44
+ @_time = time.tr(?,, ?.).to_f
45
+ self
46
+ end
47
+
48
+ def curl_command
49
+ %W(#{ConsoleUtils.curl_bin} --silent --write-out #{OUT_FORMAT} -X #{request_method} #{url}).
50
+ tap { |cmd| puts "# #{cmd.shelljoin.inspect}" unless ConsoleUtils.curl_silence }
51
+ end
52
+
53
+ def urlify(*args)
54
+ options = args.extract_options!
55
+ URI.join(ConsoleUtils.remote_endpoint, *args).
56
+ tap { |uri| uri.query = options.to_query }.to_s
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,125 @@
1
+ require 'json'
2
+ require 'active_support/core_ext/numeric'
3
+
4
+ module ConsoleUtils::RequestUtils #:nodoc:
5
+ class Requester < SimpleDelegator
6
+ REQUEST_METHODS = %i(get post put delete patch).freeze
7
+
8
+ attr_reader :url
9
+
10
+ def to_h
11
+ JSON.parse(to_s)
12
+ end
13
+
14
+ def to_body
15
+ JSON.pretty_generate(to_h)
16
+ rescue JSON::GeneratorError
17
+ to_s
18
+ end
19
+
20
+ NO_RESPONSE = Term::ANSIColor.red(" \u27A7 Empty response's body.").freeze
21
+
22
+ def preview(mth = nil)
23
+ if output = to_s.presence
24
+ case ConsoleUtils.json_formatter
25
+ when :default then puts to_body
26
+ when :jq then puts jq(output)
27
+ end
28
+
29
+ show_complete_in!
30
+ show_transfered!
31
+
32
+ yield(self) if block_given?
33
+ else
34
+ puts NO_RESPONSE
35
+ end
36
+ end
37
+
38
+ INFO_FORMAT = "%#-.50{url} | %#10{human_size} | %#10{human_time}\n".freeze
39
+
40
+ def print_info
41
+ tap { printf(INFO_FORMAT, to_info_hash) }
42
+ end
43
+
44
+ INFO_HASH_FIELDS = %i(url size time human_size human_time)
45
+
46
+ def to_info_hash
47
+ INFO_HASH_FIELDS.zip(INFO_HASH_FIELDS.map(&method(:public_send))).to_h
48
+ end
49
+
50
+ def size_downloaded
51
+ size.to_s(:human_size)
52
+ end
53
+
54
+ alias_method :human_size, :size_downloaded
55
+
56
+ def time_ms
57
+ time.to_s(:human, units: { unit: 'ms' })
58
+ end
59
+
60
+ alias_method :human_time, :time_ms
61
+
62
+ def size
63
+ @_size.bytes
64
+ end
65
+
66
+ def time
67
+ @_time.in_milliseconds
68
+ end
69
+
70
+ protected
71
+
72
+ AUTOAUTH_FORMAT = %('ID: %s' %p\n).freeze
73
+
74
+ def normalize_args
75
+ if ConsoleUtils.auto_token
76
+ uid = (@_args[0].is_a?(Hash) || @_args.empty?) ? ConsoleUtils.default_uid : @_args.shift
77
+
78
+ if uid.present?
79
+ printf(AUTOAUTH_FORMAT, uid, @_args)
80
+ opts = @_args.extract_options!
81
+ @_args.unshift(opts.tap { |x| x[ConsoleUtils.token_param] ||= __getobj__.autoken(uid) })
82
+ end
83
+ end
84
+
85
+ @_args
86
+ end
87
+
88
+
89
+ private
90
+
91
+ PBCOPY_MESSAGE = Term::ANSIColor.green(" \u27A4 Response body copied to pasteboard\n").freeze
92
+
93
+ # Copies to pasteboard
94
+ def pbcopy(content)
95
+ IO.popen('pbcopy', 'w') { |io| io << content.to_s }
96
+ puts PBCOPY_MESSAGE
97
+ end
98
+
99
+ COMPLETE_IN = Term::ANSIColor.green("Complete in %s").freeze
100
+
101
+ def show_complete_in!(reset = true)
102
+ return if @_time.nil?
103
+ puts "=> #{COMPLETE_IN % [time_ms]}"
104
+ @_time = nil
105
+ end
106
+
107
+ TRANSFERED = Term::ANSIColor.cyan("Transfered: %s").freeze
108
+
109
+ def show_transfered!(reset = true)
110
+ return if @_size.nil?
111
+ puts "=> #{TRANSFERED % [size_downloaded]}"
112
+ @_size = nil
113
+ end
114
+
115
+ private_constant :REQUEST_METHODS, :AUTOAUTH_FORMAT, :DEFAULT_UID,
116
+ :PBCOPY_MESSAGE, :NO_RESPONSE, :COMPLETE_IN, :TRANSFERED,
117
+ :INFO_FORMAT
118
+ # -
119
+
120
+ # Pretty formats json
121
+ def jq(raw)
122
+ IO.popen(ConsoleUtils.jq_command, 'r+') { |io| (io << raw).tap(&:close_write).read }
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,3 @@
1
+ module ConsoleUtils
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: console_utils
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Anton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.1'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '4.1'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5'
33
+ - !ruby/object:Gem::Dependency
34
+ name: term-ansicolor
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: awesome_print
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: benchmark-ips
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: bundler
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.9'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.9'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rake
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '10.0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '10.0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rdoc
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ description: Console Utils provides several handy tools to use in Rails Console.
118
+ email:
119
+ - anton.estum@gmail.com
120
+ executables: []
121
+ extensions: []
122
+ extra_rdoc_files: []
123
+ files:
124
+ - ".gitignore"
125
+ - ".rspec"
126
+ - ".travis.yml"
127
+ - Gemfile
128
+ - LICENSE.txt
129
+ - README.md
130
+ - Rakefile
131
+ - bin/console
132
+ - bin/setup
133
+ - console_utils.gemspec
134
+ - lib/awesome_print/proc.rb
135
+ - lib/console_utils.rb
136
+ - lib/console_utils/active_record_utils.rb
137
+ - lib/console_utils/active_record_utils/random_record.rb
138
+ - lib/console_utils/bench_utils.rb
139
+ - lib/console_utils/bench_utils/chips.rb
140
+ - lib/console_utils/core_ext/array_to_proc.rb
141
+ - lib/console_utils/other_utils.rb
142
+ - lib/console_utils/railtie.rb
143
+ - lib/console_utils/request_utils.rb
144
+ - lib/console_utils/request_utils/exap.rb
145
+ - lib/console_utils/request_utils/remo.rb
146
+ - lib/console_utils/request_utils/requester.rb
147
+ - lib/console_utils/version.rb
148
+ homepage: https://github.com/estum/console_utils
149
+ licenses:
150
+ - MIT
151
+ metadata: {}
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubyforge_project:
168
+ rubygems_version: 2.4.6
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: Groovy tools for Rails Console.
172
+ test_files: []
173
+ has_rdoc: