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

Making pod plugins an abstract command with search as default subcommand #13

Merged
merged 9 commits into from
May 2, 2014
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

## 0.1.1

* Improved output formatting and fixing some coding conventions
* Making `pod plugins` an abstract command, with `list` the default subcommand (#11 & #12)
[Olivier Halligon](https://github.com/AliSoftware)
* Added `search` subcommand to search plugins by name, author and description
* Added `search` subcommand to search plugins by name, author and description.
[Olivier Halligon](https://github.com/AliSoftware)
* Refactoring, improved output formatting and fixing some coding conventions (#10)
[Olivier Halligon](https://github.com/AliSoftware)

## 0.1.0

* Initial implementation.
[David Grandinetti](https://github.com/dbgrandi)
* Added `create` subcommand to create an empty project for a new plugin
* Added `create` subcommand to create an empty project for a new plugin.
[Boris Bügling](https://github.com/neonichu)
205 changes: 7 additions & 198 deletions lib/pod/command/plugins.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,210 +10,19 @@ class Command
#
class Plugins < Command

PLUGINS_URL = 'https://raw.githubusercontent.com/CocoaPods/cocoapods.org/master/data/plugins.json'
require 'pod/command/plugins/list'
require 'pod/command/plugins/search'
require 'pod/command/plugins/create'

attr_accessor :json
self.abstract_command = true
self.default_subcommand = 'list'

self.summary = 'Show available CocoaPods plugins'

self.description = <<-DESC
Shows the available CocoaPods plugins and if you have them installed or not.
Lists or searches the available CocoaPods plugins and show if you have them installed or not.
Also allows you to quickly create a new Cocoapods plugin using a provided template.
DESC

# Force-download the JSON
def download_json
response = REST.get(PLUGINS_URL)
if response.ok?
@json = JSON.parse(response.body)
end
end

# Tells if a gem is installed
def installed?(gemname)
if Gem::Specification.methods.include?(:find_all_by_name)
Gem::Specification.find_all_by_name(gemname).any?
else
# Fallback to Gem.available? for old versions of rubygems
Gem.available?(gemname)
end
end

# Download the JSON if not already in @json, then execute the given block
def fetch_plugins_list
UI.puts 'Downloading Plugins list...'
begin
download_json unless json
rescue => e
UI.puts e.message
end

if json
yield @json['plugins'] if block_given?
else
UI.puts 'Could not download plugins list from cocoapods.org'
end
end

def run
fetch_plugins_list do |plugins|
UI.puts "\nAvailable CocoaPods Plugins\n"

plugins.each do |plugin|
print_plugin plugin
end
end
end

# Display information about a plugin given its hash
def print_plugin(plugin)
plugin_name = "-> #{plugin['name']}"
plugin_colored_name = installed?(plugin['gem']) ? plugin_name.green : plugin_name.yellow

UI.title(plugin_colored_name, '', 1) do
UI.puts_indented plugin['description']
UI.labeled('Gem', plugin['gem'])
UI.labeled('URL', plugin['url'])
UI.labeled('Author', plugin['author']) if self.verbose?
end
end

#-----------------------------------------------------------------------#

# The search subcommand. Used to search a plugin in the list of known plugins,
# searching into the name and description fields
#
class Search < Plugins
self.summary = 'Search for known plugins'

self.description = <<-DESC
Search plugins whose name contains the given text (ignoring case).
With --full, search by name but also author and description
DESC

self.arguments = 'QUERY'

def self.options
[
["--full", "Search by name, author, and description"],
].concat(super.reject { |option, _| option == '--silent' })
end

def initialize(argv)
@full_text_search = argv.flag?('full')
@query = argv.shift_argument unless argv.arguments.empty?
super
end

def validate!
super
help! "A search query is required." if @query.nil? || @query.empty?
begin
/#{@query}/
rescue RegexpError
help! "A valid regular expression is required."
end
end

def run
fetch_plugins_list do |plugins|
UI.puts "\nAvailable CocoaPods Plugins matching '#{@query}'\n"

query_regexp = /#{@query}/i
plugins.each do |plugin|
texts = [plugin['name']]
if @full_text_search
texts << plugin['author'] if plugin['author']
texts << plugin['description'] if plugin['description']
end
print_plugin plugin unless texts.grep(query_regexp).empty?
end
end
end

end

#-----------------------------------------------------------------------#

# The create subcommand. Used to create a new plugin using either the
# default template (CocoaPods/cocoapods-plugin-template) or a custom
# template
#
class Create < Plugins
self.summary = 'Creates a new plugin'

self.description = <<-DESC
Creates a scaffold for the development of a new plugin according to the CocoaPods best practices.
If a `TEMPLATE_URL`, pointing to a git repo containing a compatible template, is specified, it will be used in place of the default one.
DESC

self.arguments = 'NAME [TEMPLATE_URL]'

def initialize(argv)
@name = argv.shift_argument
@template_url = argv.shift_argument
super
end

def validate!
super
help! 'A name for the plugin is required.' if @name.nil? || @name.empty?
help! 'The plugin name cannot contain spaces.' if @name.match(/\s/)
end

def run
clone_template
configure_template
end

private

#----------------------------------------#

# !@group Private helpers

extend Executable
executable :git
executable :ruby

TEMPLATE_REPO = 'https://github.com/CocoaPods/cocoapods-plugin-template.git'
TEMPLATE_INFO_URL = 'https://github.com/CocoaPods/cocoapods-plugin-template'

# Clones the template from the remote in the working directory using
# the name of the plugin.
#
# @return [void]
#
def clone_template
UI.section("Creating `#{@name}` plugin") do
git! "clone '#{template_repo_url}' #{@name}"
end
end

# Runs the template configuration utilities.
#
# @return [void]
#
def configure_template
UI.section('Configuring template') do
Dir.chdir(@name) do
if File.file? 'configure'
system "./configure #{@name}"
else
UI.warn 'Template does not have a configure file.'
end
end
end
end

# Checks if a template URL is given else returns the TEMPLATE_REPO URL
#
# @return String
#
def template_repo_url
@template_url || TEMPLATE_REPO
end
end

end
end
end
87 changes: 87 additions & 0 deletions lib/pod/command/plugins/create.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
module Pod
class Command
class Plugins

# The create subcommand. Used to create a new plugin using either the
# default template (CocoaPods/cocoapods-plugin-template) or a custom
# template
#
class Create < Plugins

self.summary = 'Creates a new plugin'
self.description = <<-DESC
Creates a scaffold for the development of a new plugin according to the CocoaPods best practices.
If a `TEMPLATE_URL`, pointing to a git repo containing a compatible template, is specified, it will be used in place of the default one.
DESC

self.arguments = 'NAME [TEMPLATE_URL]'

def initialize(argv)
@name = argv.shift_argument
@template_url = argv.shift_argument
super
end

def validate!
super
help! 'A name for the plugin is required.' if @name.nil? || @name.empty?
help! 'The plugin name cannot contain spaces.' if @name.match(/\s/)
end

def run
clone_template
configure_template
end

#----------------------------------------#

private

# !@group Private helpers

extend Executable
executable :git
executable :ruby

TEMPLATE_REPO = 'https://github.com/CocoaPods/cocoapods-plugin-template.git'
TEMPLATE_INFO_URL = 'https://github.com/CocoaPods/cocoapods-plugin-template'

# Clones the template from the remote in the working directory using
# the name of the plugin.
#
# @return [void]
#
def clone_template
UI.section("Creating `#{@name}` plugin") do
git! "clone '#{template_repo_url}' #{@name}"
end
end

# Runs the template configuration utilities.
#
# @return [void]
#
def configure_template
UI.section('Configuring template') do
Dir.chdir(@name) do
if File.file? 'configure'
system "./configure #{@name}"
else
UI.warn 'Template does not have a configure file.'
end
end
end
end

# Checks if a template URL is given else returns the TEMPLATE_REPO URL
#
# @return String
#
def template_repo_url
@template_url || TEMPLATE_REPO
end
end

end
end
end
32 changes: 32 additions & 0 deletions lib/pod/command/plugins/list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require 'pod/plugins_helper'

module Pod
class Command
class Plugins

# The list subcommand. Used to list all known plugins
#
class List < Plugins

self.summary = 'List all known plugins'
self.description = <<-DESC
List all known plugins (according to the list hosted on github.com/CocoaPods/cocoapods.org)
DESC

def self.options
super.reject { |option, _| option == '--silent' }
Copy link
Member

Choose a reason for hiding this comment

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

It might make sense to port this logic to CLAide /c @alloy

Copy link
Member

Choose a reason for hiding this comment

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

Not sure, it’s quite simple to grasp if you know Ruby. What would you propose?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Allow I agree that this is pretty annoying to have to .concat(super).reject { } every time we create a subcommand (to get the common options like --verbose and --help and all with Array#concat(super)… but except some like --silent in some cases with Array#reject)

Maybe we can have helper methods in Pod::Command if not in CLAide::Command, like self.common_options (even with some parameter to handle multiple cases like commands designated to only output stuff and do nothing else, for which options like --silent wouldn't have much sense), so that we could Array#concat with this instead of super?

At least I'm sure it's worth thinking about sthg to avoid this concat+reject pattern that we observe in a lot of pod subcommands.

Copy link
Member

Choose a reason for hiding this comment

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

I think it’s definitely worth it to create a CLAide ticket about it to remind us to reflect on this in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@alloy @irrationalfab Ticket opened!

end

def run
plugins = PluginsHelper.known_plugins

UI.title 'Available CocoaPods Plugins:' do
plugins.each { |plugin| PluginsHelper.print_plugin plugin, self.verbose? }
end
end

end

end
end
end
Loading