console_utils 0.1.0

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