Skip to content

Commit

Permalink
CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmacaulay committed Nov 17, 2010
1 parent 9416acf commit 1dbff64
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 8 deletions.
4 changes: 4 additions & 0 deletions bin/shopify
@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
require File.expand_path('../../lib/shopify_api',__FILE__)
require File.expand_path('../../lib/shopify_api/cli',__FILE__)
ShopifyAPI::Cli.start(ARGV)
156 changes: 156 additions & 0 deletions lib/shopify_api/cli.rb
@@ -0,0 +1,156 @@
require 'thor'

module ShopifyAPI
class Cli < Thor
include Thor::Actions

class ConfigFileError < StandardError
end

desc "list", "list available connections"
def list
available_connections.each do |c|
prefix = default?(c) ? " * " : " "
puts prefix + c
end
end

desc "add CONNECTION", "create a config file for a connection named CONNECTION"
def add(connection)
file = config_file(connection)
if File.exist?(file)
raise ConfigFileError, "There is already a config file at #{file}"
else
config = {'protocol' => 'https'}
config['domain'] = ask("Domain? (leave blank for #{connection}.myshopify.com)")
config['domain'] = "#{connection}.myshopify.com" if config['domain'].blank?
puts "\nopen https://#{config['domain']}/admin/api in your browser to get API credentials\n"
config['api_key'] = ask("API key?")
config['password'] = ask("Password?")
create_file(file, config.to_yaml)
end
if available_connections.one?
default(connection)
end
end

desc "remove CONNECTION", "remove the config file for CONNECTION"
def remove(connection)
file = config_file(connection)
if File.exist?(file)
remove_file(default_symlink) if default?(connection)
remove_file(file)
else
no_config_file_error(file)
end
end

desc "edit [CONNECTION]", "open the config file for CONNECTION with your default editor"
def edit(connection=nil)
file = config_file(connection)
if File.exist?(file)
if ENV['EDITOR'].present?
`#{ENV['EDITOR']} #{file}`
else
puts "Please set an editor in the EDITOR environment variable"
end
else
no_config_file_error(file)
end
end

desc "show [CONNECTION]", "output the location and contents of the CONNECTION's config file"
def show(connection=nil)
connection ||= default_connection
file = config_file(connection)
if File.exist?(file)
puts file
puts `cat #{file}`
else
no_config_file_error(file)
end
end

desc "default [CONNECTION]", "show the default connection, or make CONNECTION the default"
def default(connection=nil)
if connection
target = config_file(connection)
if File.exist?(target)
remove_file(default_symlink)
`ln -s #{target} #{default_symlink}`
else
no_config_file_error(file)
end
end
if File.exist?(default_symlink)
puts "Default connection is #{default_connection}"
else
puts "There is no default connection set"
end
end

desc "console [CONNECTION]", "start an API console for CONNECTION"
def console(connection=nil)
file = config_file(connection)

config = YAML.load(File.read(file))
puts "using #{config['domain']}"
ShopifyAPI::Base.site = site_from_config(config)

require 'irb'
require 'irb/completion'
ARGV.clear
IRB.start
end

private

def shop_config_dir
@shop_config_dir ||= File.join(ENV['HOME'], '.shopify', 'shops')
end

def default_symlink
@default_symlink ||= File.join(shop_config_dir, 'default')
end

def config_file(connection)
if connection
File.join(shop_config_dir, "#{connection}.yml")
else
default_symlink
end
end

def site_from_config(config)
protocol = config['protocol'] || 'https'
api_key = config['api_key']
password = config['password']
domain = config['domain']

ShopifyAPI::Base.site = "#{protocol}://#{api_key}:#{password}@#{domain}/admin"
end

def available_connections
@available_connections ||= begin
pattern = File.join(shop_config_dir, "*.yml")
Dir.glob(pattern).map { |f| File.basename(f, ".yml") }
end
end

def default_connection_target
@default_connection_target ||= File.readlink(default_symlink)
end

def default_connection
@default_connection ||= File.basename(default_connection_target, ".yml")
end

def default?(connection)
default_connection == connection
end

def no_config_file_error(filename)
raise ConfigFileError, "There is no config file at #{file}"
end
end
end
19 changes: 11 additions & 8 deletions shopify_api.gemspec
Expand Up @@ -76,6 +76,7 @@ Copyright (c) 2009 "JadedPixel inc.". See LICENSE for details.
"README.rdoc",
"Rakefile",
"lib/shopify_api.rb",
"lib/shopify_api/cli.rb",
"shopify_api.gemspec",
"test/order_test.rb",
"test/shopify_api_test.rb",
Expand All @@ -92,18 +93,20 @@ Copyright (c) 2009 "JadedPixel inc.". See LICENSE for details.
"test/shopify_api_test.rb",
"test/test_helper.rb"
]
s.executables = ['shopify']

if s.respond_to? :specification_version then
if s.respond_to? :specification_version
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3

if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<activeresource>, [">= 2.2.2"])
else
s.add_dependency(%q<activeresource>, [">= 2.2.2"])
end
end

s.add_dependency("activeresource", [">= 2.2.2"])
s.add_dependency("thor", [">= 0.14.4"])

if s.respond_to?(:add_development_dependency)
s.add_development_dependency("mocha", ">= 0.9.8")
else
s.add_dependency(%q<activeresource>, [">= 2.2.2"])
s.add_dependency("mocha", ">= 0.9.8")
end
end

109 changes: 109 additions & 0 deletions test/cli_test.rb
@@ -0,0 +1,109 @@
require 'test_helper'
require 'shopify_api/cli'
require 'fileutils'

class CliTest < Test::Unit::TestCase
def setup
@test_home = File.join(File.expand_path(File.dirname(__FILE__)), 'files', 'home')
@shop_config_dir = File.join(@test_home, '.shopify', 'shops')
@default_symlink = File.join(@shop_config_dir, 'default')
`rm -rf #{@test_home}`
ENV['HOME'] = @test_home
@cli = ShopifyAPI::Cli.new

FileUtils.mkdir_p(@shop_config_dir)
File.open(config_file('foo'), 'w') do |file|
file.puts valid_options.merge('domain' => 'foo.myshopify.com').to_yaml
end
File.symlink(config_file('foo'), @default_symlink)
File.open(config_file('bar'), 'w') do |file|
file.puts valid_options.merge('domain' => 'bar.myshopify.com').to_yaml
end
end

def teardown
`rm -rf #{@test_home}`
end

test "add with blank domain" do
`rm -rf #{@shop_config_dir}/*`
$stdout.expects(:print).with("Domain? (leave blank for foo.myshopify.com) ")
$stdout.expects(:print).with("API key? ")
$stdout.expects(:print).with("Password? ")
$stdin.expects(:gets).times(3).returns("", "key", "pass")
@cli.expects(:puts).with("\nopen https://foo.myshopify.com/admin/api in your browser to get API credentials\n")
@cli.expects(:puts).with("Default connection is foo")

@cli.add('foo')

config = YAML.load(File.read(config_file('foo')))
assert_equal 'foo.myshopify.com', config['domain']
assert_equal 'key', config['api_key']
assert_equal 'pass', config['password']
assert_equal 'https', config['protocol']
assert_equal config_file('foo'), File.readlink(@default_symlink)
end

test "add with explicit domain" do
`rm -rf #{@shop_config_dir}/*`
$stdout.expects(:print).with("Domain? (leave blank for foo.myshopify.com) ")
$stdout.expects(:print).with("API key? ")
$stdout.expects(:print).with("Password? ")
$stdin.expects(:gets).times(3).returns("bar.myshopify.com", "key", "pass")
@cli.expects(:puts).with("\nopen https://bar.myshopify.com/admin/api in your browser to get API credentials\n")
@cli.expects(:puts).with("Default connection is foo")

@cli.add('foo')

config = YAML.load(File.read(config_file('foo')))
assert_equal 'bar.myshopify.com', config['domain']
end

test "list" do
@cli.expects(:puts).with(" bar")
@cli.expects(:puts).with(" * foo")

@cli.list
end

test "show default" do
@cli.expects(:puts).with("Default connection is foo")

@cli.default
end

test "set default" do
@cli.expects(:puts).with("Default connection is bar")

@cli.default('bar')

assert_equal config_file('bar'), File.readlink(@default_symlink)
end

test "remove default connection" do
@cli.remove('foo')

assert !File.exist?(@default_symlink)
assert !File.exist?(config_file('foo'))
assert File.exist?(config_file('bar'))
end

test "remove non-default connection" do
@cli.remove('bar')

assert_equal config_file('foo'), File.readlink(@default_symlink)
assert File.exist?(config_file('foo'))
assert !File.exist?(config_file('bar'))
end

private

def valid_options
{'domain' => 'snowdevil.myshopify.com', 'api_key' => 'key', 'password' => 'pass', 'protocol' => 'https'}
end

def config_file(connection)
File.join(@shop_config_dir, "#{connection}.yml")
end

end
1 change: 1 addition & 0 deletions test/test_helper.rb
@@ -1,5 +1,6 @@
require 'rubygems'
require 'test/unit'
require 'mocha'

$LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
Expand Down

0 comments on commit 1dbff64

Please sign in to comment.