Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CLI - Integrate fakerbot 🤖 #1507

Merged
merged 17 commits into from Mar 3, 2019
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 43 additions & 12 deletions Gemfile.lock
Expand Up @@ -3,26 +3,40 @@ PATH
specs:
faker (1.9.1)
i18n (>= 0.7)
pastel (~> 0.7.2)
thor (~> 0.20.0)
tty-pager (~> 0.12.0)
tty-screen (~> 0.6.5)
tty-tree (~> 0.2.0)

GEM
remote: https://rubygems.org/
specs:
ast (2.4.0)
concurrent-ruby (1.0.5)
coderay (1.1.2)
concurrent-ruby (1.1.4)
docile (1.3.1)
i18n (1.1.1)
equatable (0.5.0)
i18n (1.4.0)
concurrent-ruby (~> 1.0)
jaro_winkler (1.5.1)
jaro_winkler (1.5.2)
json (2.1.0)
method_source (0.9.2)
minitest (5.11.3)
parallel (1.12.1)
parser (2.5.1.2)
parser (2.5.3.0)
ast (~> 2.4.0)
pastel (0.7.2)
equatable (~> 0.5.0)
tty-color (~> 0.4.0)
power_assert (1.1.3)
powerpack (0.1.2)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rainbow (3.0.0)
rake (12.3.1)
rubocop (0.59.2)
rubocop (0.59.1)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.5, != 2.5.1.1)
Expand All @@ -36,22 +50,39 @@ GEM
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
strings (0.1.4)
strings-ansi (~> 0.1.0)
unicode-display_width (~> 1.4.0)
unicode_utils (~> 1.4.0)
strings-ansi (0.1.0)
test-unit (3.2.8)
power_assert
thor (0.20.3)
timecop (0.9.1)
unicode-display_width (1.4.0)
tty-color (0.4.3)
tty-pager (0.12.0)
strings (~> 0.1.4)
tty-screen (~> 0.6)
tty-which (~> 0.4)
tty-screen (0.6.5)
tty-tree (0.2.0)
tty-which (0.4.0)
unicode-display_width (1.4.1)
unicode_utils (1.4.0)

PLATFORMS
ruby

DEPENDENCIES
bundler (= 1.16.4)
faker!
minitest
rake
rubocop
simplecov
test-unit
timecop
minitest (= 5.11.3)
pry (= 0.12.2)
rake (= 12.3.1)
rubocop (= 0.59.1)
simplecov (= 0.16.1)
test-unit (= 3.2.8)
timecop (= 0.9.1)

BUNDLED WITH
1.16.4
14 changes: 11 additions & 3 deletions README.md
Expand Up @@ -192,6 +192,14 @@ Faker::Name.name #=> "Christophe Bartell"
Faker::Internet.email #=> "kirsten.greenholt@corkeryfisher.info"
```

### CLI
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change should go in our unreleased_README.md.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good shout. 👍


Usage Instructions [available here](https://github.com/stympy/faker/blob/master/lib/cli/README.md)

```bash
$ faker
```

### Ensuring unique values

Prefix your method call with `unique`. For example:
Expand Down Expand Up @@ -256,15 +264,15 @@ en-au-ocker:
faker:
name:
# Existing faker field, new data
first_name:
first_name:
- Charlotte
- Ava
- Chloe
- Emily

# New faker fields
ocker_first_name:
- Bazza
ocker_first_name:
- Bazza
- Bluey
- Davo
- Johno
Expand Down
19 changes: 19 additions & 0 deletions bin/faker
@@ -0,0 +1,19 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

lib_path = File.expand_path('../lib', __dir__)
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)

require 'cli'

Signal.trap('INT') do
warn("\n#{caller.join("\n")}: interrupted")
exit(1)
end

begin
Faker::CLI::Base.start
rescue Faker::CLI::Base::Error => err
puts "ERROR: #{err.message}"
exit 1
end
51 changes: 31 additions & 20 deletions faker.gemspec
Expand Up @@ -3,26 +3,37 @@
$LOAD_PATH.push File.expand_path('lib', __dir__)
require 'faker/version'

Gem::Specification.new do |s|
s.name = 'faker'
s.version = Faker::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ['Benjamin Curtis']
s.email = ['benjamin.curtis@gmail.com']
s.homepage = 'https://github.com/stympy/faker'
s.summary = 'Easily generate fake data'
s.description = 'Faker, a port of Data::Faker from Perl, is used to easily generate fake data: names, addresses, phone numbers, etc.'
s.license = 'MIT'
Gem::Specification.new do |spec|
spec.name = 'faker'
spec.version = Faker::VERSION
spec.platform = Gem::Platform::RUBY
spec.authors = ['Benjamin Curtis']
spec.email = ['benjamin.curtis@gmail.com']

s.add_runtime_dependency('i18n', '>= 0.7')
s.add_development_dependency('minitest')
s.add_development_dependency('rake')
s.add_development_dependency('rubocop')
s.add_development_dependency('simplecov')
s.add_development_dependency('test-unit')
s.add_development_dependency('timecop')
s.required_ruby_version = '>= 2.3'
spec.summary = 'Easily generate fake data'
spec.description = 'Faker, a port of Data::Faker from Perl, is used to easily generate fake data: names, addresses, phone numbers, etc.'
spec.homepage = 'https://github.com/stympy/faker'
spec.license = 'MIT'

s.files = Dir['lib/**/*'] + %w[History.md License.txt CHANGELOG.md README.md]
s.require_paths = ['lib']
spec.files = Dir['lib/**/*'] + %w[History.md License.txt CHANGELOG.md README.md]
spec.bindir = 'bin'
spec.executables = ['faker']
spec.require_paths = ['lib']
spec.required_ruby_version = '>= 2.3'

spec.add_dependency('i18n', '>= 0.7')
spec.add_dependency('pastel', '~> 0.7.2')
spec.add_dependency('thor', '~> 0.20.0')
spec.add_dependency('tty-pager', '~> 0.12.0')
spec.add_dependency('tty-screen', '~> 0.6.5')
spec.add_dependency('tty-tree', '~> 0.2.0')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding these dependencies is a pretty big deal. Are we comfortable with them? I saw the terminal response. It's pretty cool.

Thoughts? @stympy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a valid concern, from my POV, these libraries go a long way in making the CLI interface easier to work with. 🙂 The alternative would be to write it all ourselves which I'm not sure about

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, I find all these dependencies to be a big deal. I opened an issue about it (#1642) and plan to stay on 1.9.3 for the time being.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@myronmarston your concern is valid.

@akabiru would you agree to remove these dependencies and just show a formatted list of searched results?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey folks, apologies for the very delayed response (on vacation). I think the move to a separate gem is the sensible approach. And allows users to opt-in into using the gem.

It did start as a separate gem , no strong objections on this one. 🙂

@vbrazo I'm happy to assist with the extraction &/migration as well.


spec.add_development_dependency('bundler', '1.16.4')
spec.add_development_dependency('minitest', '5.11.3')
spec.add_development_dependency('pry', '0.12.2')
spec.add_development_dependency('rake', '12.3.1')
spec.add_development_dependency('rubocop', '0.59.1')
spec.add_development_dependency('simplecov', '0.16.1')
spec.add_development_dependency('test-unit', '3.2.8')
spec.add_development_dependency('timecop', '0.9.1')
end
53 changes: 53 additions & 0 deletions lib/cli.rb
@@ -0,0 +1,53 @@
# frozen_string_literal: true

require 'thor'

require 'cli/commands/list'
require 'cli/commands/search'
require 'faker/version'

module Faker
module CLI
class Base < Thor
Error = Class.new(StandardError)
# Do not print depracation warnings; the CLI will do that
Gem::Deprecate.skip = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to turn this false after executing the operations?

I'm asking you because we're using namespaces and there are a lot of deprecation warnings. Are we assuming that users will always use the cli?

Copy link
Contributor Author

@akabiru akabiru Feb 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to turn this false after executing the operations?

Thanks! This makes perfect sense to me, I had missed that. I'll make the change. ⭐️

Background

Good call here, the intention was to disable the default deprecation warnings only in the context of the CLI. since it checks for deprecated methods and marks them.

Previously, we'd see the full default deprecation print out after the CLI exited as capture in https://github.com/akabiru/fakerbot/issues/7 - thus the need to gracefully handle the deprecation warnings (in the context of the CLI)


desc 'version', 'Faker version'
def version
puts "v#{Faker::VERSION}"
end
map %w[--version -v] => :version

desc 'list', 'List all Faker constants'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
method_option :show_methods, aliases: '-m', type: :boolean, default: true,
desc: 'Display Faker constants with methods'
method_option :verbose, aliases: '-v', type: :boolean,
desc: 'Include sample Faker output'
def list(*)
if options[:help]
invoke :help, ['list']
else
Faker::CLI::Commands::List.new(options).execute
end
end

desc 'search [Faker]', 'Search Faker method(s)'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
method_option :show_methods, aliases: '-m', type: :boolean, default: true,
desc: 'Display Faker constants with methods'
method_option :verbose, aliases: '-v', type: :boolean,
desc: 'Include sample Faker output'
def search(query)
if options[:help]
invoke :help, ['search']
else
Faker::CLI::Commands::Search.new(options).execute(query)
end
end
end
end
end
55 changes: 55 additions & 0 deletions lib/cli/README.md
@@ -0,0 +1,55 @@
# faker (cli)

## Usage

1.) Run a quick lookup

```bash
$ faker search name
# Faker::SwordArtOnline
# └── real_name
# └── game_name
# Faker::Superhero
# └── name
# ....
```

2.) List methods

```sh
$ faker list
# Faker::BackToTheFuture
# ├── quote
# ├── date
# └── character
# Faker::Finance
# └── credit_card
# ....
```

`faker` also includes an option to display sample output via the `--verbose` or `-v` flag. :wink:

3.)

```sh
$ faker list -v
# Faker::Appliance
# ├── brand=> Whirlpool
# └── equipment=> Sump pump
# Faker::UmphreysMcgee
# └── song=> Headphones & Snowcones
$ faker search name -v
# Faker::App
# └── name=> Subin
# Faker::Address
# └── street_name=> Percy Landing
# ....
```

## Features! :sunglasses: :dancers:

- [x] List classes with methods E.g. Faker::FunnyName is displayed with `.name`,`.first_name` e.t.c.
- [x] Expand search to Faker::Base sub classes
- [x] Paginate results :book:

![screenshot 2019-01-05 at 03 02 08](https://user-images.githubusercontent.com/17295175/50717135-59d85780-1096-11e9-8d0d-eca95646644d.jpg)
24 changes: 24 additions & 0 deletions lib/cli/command.rb
@@ -0,0 +1,24 @@
# frozen_string_literal: true

require 'forwardable'

require_relative 'renderer'

module Faker
module CLI
class Command
extend Forwardable

def_delegators :command, :run
attr_reader :options

def initialize(options)
@options = options
end

def render(result, output)
Renderer.call(result, options, output)
end
end
end
end
17 changes: 17 additions & 0 deletions lib/cli/commands/list.rb
@@ -0,0 +1,17 @@
# frozen_string_literal: true

require_relative '../command'
require_relative '../reflectors/list'

module Faker
module CLI
module Commands
class List < Command
def execute(output: $stdout)
result = Reflectors::List.call(options)
render(result, output)
end
end
end
end
end
29 changes: 29 additions & 0 deletions lib/cli/commands/search.rb
@@ -0,0 +1,29 @@
# frozen_string_literal: true

require_relative '../command'
require_relative '../reflectors/search'

module Faker
module CLI
module Commands
class Search < Command
def execute(input, output: $stdout)
result = Reflectors::Search.call(input)
render(result, output)
end

private

def render(result, output)
return not_found(output) if result.empty?

super(result, output)
end

def not_found(output)
output.puts "\nSorry, we couldn't find a match 😢", "\n"
end
end
end
end
end