relish 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,24 +4,26 @@ Feature: Help
4
4
  The `relish help` command displays all available commands
5
5
  along with a description of each.
6
6
 
7
- The `relish help:<command>` option will display help text
8
- for that particular command.
9
-
10
7
  Scenario: View all available commands with the help command
11
8
  When I successfully run "relish help"
12
9
  Then the output should contain exactly:
13
10
  """
14
11
  === Available Commands
15
12
 
16
- help # show this usage
17
- config # display the contents of your options file
18
- config:show # display the contents of your options file
19
- config:add --<option> <value> # add a configuration option to your options file
20
- projects # list your projects
21
- projects:list # list your projects
22
- projects:add <org_or_user_handle>/<project_handle> # add a project
23
- projects:remove <org_or_user_handle>/<project_handle> # remove a project
24
- push # push features to relishapp.com
13
+ help # show this usage
14
+ config # display the contents of your options file
15
+ config:add --<option> <value> # add a configuration option to your options file
16
+ projects # list your projects
17
+ projects:add <org_or_user_handle>/<project_handle> # add a project
18
+ # append :private to make the project private
19
+ # example: relish projects:add rspec/rspec-core:private
20
+ projects:remove <org_or_user_handle>/<project_handle> # remove a project
21
+ push # push features to relishapp.com
22
+ collab # list the collaborators for a project
23
+ collab:add <org_or_user_handle>/<project_handle>:<collaborator_handle_or_email> # add a collaborator to a project
24
+ # example: relish collab:add rspec/rspec-core:justin
25
+ collab:remove <org_or_user_handle>/<project_handle>:<collaborator_handle_or_email> # remove a collaborator from a project
26
+ # example: relish collab:remove rspec/rspec-core:justin
25
27
 
26
28
  """
27
29
 
@@ -1,3 +1,5 @@
1
+ require 'relish/core_ext'
2
+
1
3
  module Relish
2
4
  class << self
3
5
 
@@ -1,10 +1,11 @@
1
1
  require 'relish'
2
2
  require 'relish/helpers'
3
3
  require 'relish/commands/base'
4
- require 'relish/commands/push'
4
+ require 'relish/commands/collab'
5
5
  require 'relish/commands/config'
6
- require 'relish/commands/projects'
7
6
  require 'relish/commands/help'
7
+ require 'relish/commands/projects'
8
+ require 'relish/commands/push'
8
9
 
9
10
  module Relish
10
11
  module Command
@@ -1,4 +1,5 @@
1
1
  require 'yaml'
2
+ require 'json'
2
3
  require 'relish/ui'
3
4
  require 'relish/options_file'
4
5
  require 'relish/commands/dsl'
@@ -81,6 +82,14 @@ module Relish
81
82
  @ui ||= Ui.new
82
83
  end
83
84
 
85
+ def json_parse(response, &block)
86
+ JSON.parse(response).inject([]) do |parsed_output, hash|
87
+ parsed_output << block.call(hash)
88
+ end.join("\n")
89
+ rescue JSON::ParserError
90
+ response
91
+ end
92
+
84
93
  end
85
94
  end
86
95
  end
@@ -0,0 +1,44 @@
1
+ module Relish
2
+ module Command
3
+ class Collab < Base
4
+
5
+ desc 'list the collaborators for a project'
6
+ command :default do
7
+ puts format(resource[resource_path].get(:accept => :json))
8
+ end
9
+
10
+ usage 'collab:add <org_or_user_handle>/<project_handle>:' +
11
+ '<collaborator_handle_or_email>'
12
+ desc ['add a collaborator to a project',
13
+ 'example: relish collab:add rspec/rspec-core:justin'].join("\n")
14
+ command :add do
15
+ puts resource[resource_path].post(:handle_or_email => handle_or_email)
16
+ end
17
+
18
+ usage 'collab:remove <org_or_user_handle>/<project_handle>:' +
19
+ '<collaborator_handle_or_email>'
20
+ desc ['remove a collaborator from a project',
21
+ 'example: relish collab:remove rspec/rspec-core:justin'].join("\n")
22
+ command :remove do
23
+ puts resource["#{resource_path}/#{handle_or_email}"].delete
24
+ end
25
+
26
+ private
27
+
28
+ def resource_path
29
+ "projects/#{@param.remove_option}/memberships"
30
+ end
31
+
32
+ def handle_or_email
33
+ @param.extract_option
34
+ end
35
+
36
+ def format(response)
37
+ json_parse(response) do |hash|
38
+ "#{hash['user']['handle']} (#{hash['user']['email']})"
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -3,11 +3,7 @@ module Relish
3
3
  class Config < Base
4
4
 
5
5
  desc 'display the contents of your options file'
6
- command :default => :show
7
-
8
- usage 'config:show'
9
- desc 'display the contents of your options file'
10
- command :show do
6
+ command :default do
11
7
  puts(if File.exists?(Relish.local_options_file)
12
8
  IO.read(Relish.local_options_file)
13
9
  else
@@ -1,4 +1,4 @@
1
- require 'relish/commands/dsl/base'
1
+ require 'relish/commands/dsl/context_class'
2
2
  require 'relish/commands/dsl/option'
3
3
  require 'relish/commands/dsl/command'
4
4
  require 'relish/commands/dsl/help_text'
@@ -1,10 +1,11 @@
1
1
  module Relish
2
2
  module Command
3
3
  module Dsl
4
- class Command < Base
4
+ class Command
5
+ include ContextClass
5
6
 
6
7
  def define(name, &block)
7
- context_eval do
8
+ context_class_eval do
8
9
  define_method(name) do
9
10
  begin
10
11
  instance_exec(&block)
@@ -14,7 +15,7 @@ module Relish
14
15
  end
15
16
  end
16
17
  end
17
- HelpText.add(name, context_name)
18
+ HelpText.add(name, context_class_name)
18
19
  end
19
20
 
20
21
  end
@@ -0,0 +1,23 @@
1
+ module Relish
2
+ module Command
3
+ module Dsl
4
+ module ContextClass
5
+
6
+ attr_reader :context_class
7
+
8
+ def initialize(context_class)
9
+ @context_class = context_class
10
+ end
11
+
12
+ def context_class_eval(&block)
13
+ context_class.class_eval(&block)
14
+ end
15
+
16
+ def context_class_name
17
+ context_class.name.split('::').last.downcase
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -34,6 +34,12 @@ module Relish
34
34
  def clear_commands
35
35
  @commands = {}
36
36
  end
37
+
38
+ def max_usage_length
39
+ commands.values.map {|v|
40
+ v.map {|v| v.keys.to_s.length }.max
41
+ }.max
42
+ end
37
43
  end
38
44
 
39
45
  end
@@ -1,13 +1,14 @@
1
1
  module Relish
2
2
  module Command
3
3
  module Dsl
4
- class Option < Base
4
+ class Option
5
+ include ContextClass
5
6
 
6
7
  def define(name, options = {})
7
8
  name = name.to_s
8
9
  default_proc = options[:default] || Proc.new {}
9
10
 
10
- context_eval do
11
+ context_class_eval do
11
12
  define_method(name) do
12
13
  cli_options[name] ||
13
14
  local_options_file[name] ||
@@ -1,29 +1,46 @@
1
- require 'yaml'
2
-
3
1
  module Relish
4
2
  module Command
5
3
  class Help < Base
6
4
 
7
- desc 'show this usage'
5
+ desc 'show this usage'
8
6
  command :default do
9
7
  puts "=== Available Commands\n\n"
10
-
11
8
  Dsl::HelpText.commands.each do |command, list|
12
- list.each do |hash|
13
- usage, description = *hash.to_a.flatten
14
- usage = command if usage == 'default'
15
- puts "#{usage.ljust(max_command_length)} # #{description}"
16
- end
9
+ list.each {|hash| Formatter.new(command, hash).format }
17
10
  end
18
11
  end
19
12
 
20
- private
13
+ class Formatter
14
+ attr_reader :command, :usage, :description
15
+
16
+ def initialize(command, hash)
17
+ @command = command
18
+ @usage, @description = *hash.to_a.flatten
19
+ end
20
+
21
+ def usage
22
+ @usage == 'default' ? @command : @usage
23
+ end
24
+
25
+ def format
26
+ description.split("\n").each_with_index do |part, index|
27
+ puts "#{format_usage(index)} # #{part}"
28
+ end
29
+ end
30
+
31
+ def format_usage(index)
32
+ if index.zero?
33
+ usage.ljust(max_usage_length)
34
+ else
35
+ " " * max_usage_length
36
+ end
37
+ end
21
38
 
22
- def max_command_length
23
- Dsl::HelpText.commands.values.map {|v|
24
- v.map {|v| v.keys.to_s.length }.max
25
- }.max
39
+ def max_usage_length
40
+ Dsl::HelpText.max_usage_length
41
+ end
26
42
  end
43
+
27
44
  end
28
45
  end
29
46
  end
@@ -1,24 +1,18 @@
1
- require 'rubygems'
2
- require 'json'
3
-
4
1
  module Relish
5
2
  module Command
6
3
  class Projects < Base
7
-
8
- desc 'list your projects'
9
- command :default => :list
10
-
11
- usage 'projects:list'
4
+
12
5
  desc 'list your projects'
13
- command :list do
14
- response = resource['projects'].get(:accept => :json)
15
- puts format(response)
6
+ command :default do
7
+ puts format(resource['projects'].get(:accept => :json))
16
8
  end
17
9
 
18
10
  usage 'projects:add <org_or_user_handle>/<project_handle>'
19
- desc 'add a project'
11
+ desc ['add a project',
12
+ 'append :private to make the project private',
13
+ 'example: relish projects:add rspec/rspec-core:private'].join("\n")
20
14
  command :add do
21
- puts resource['projects'].post(:handle => @param)
15
+ puts resource['projects'].post(:handle => handle, :private => private?)
22
16
  end
23
17
 
24
18
  usage 'projects:remove <org_or_user_handle>/<project_handle>'
@@ -29,12 +23,19 @@ module Relish
29
23
 
30
24
  private
31
25
  def format(response)
32
- json = JSON.parse(response)
33
- json.map do |hash|
26
+ json_parse(response) do |hash|
34
27
  result = hash['project']['full_handle']
35
28
  result << " (private)" if hash['project']['private']
36
29
  result
37
- end.join("\n")
30
+ end
31
+ end
32
+
33
+ def handle
34
+ @param.remove_option
35
+ end
36
+
37
+ def private?
38
+ @param.extract_option == 'private'
38
39
  end
39
40
 
40
41
  end
@@ -1,9 +1,7 @@
1
- require 'rubygems'
2
1
  require 'zlib'
3
2
  require 'archive/tar/minitar'
4
3
  require 'stringio'
5
4
  require 'rest_client'
6
- require 'relish/commands/help'
7
5
 
8
6
  module Relish
9
7
  module Command
@@ -0,0 +1,15 @@
1
+ module Relish
2
+ module StringExtensions
3
+ def extract_option
4
+ split(':')[1]
5
+ end
6
+
7
+ def remove_option
8
+ split(':')[0]
9
+ end
10
+ end
11
+ end
12
+
13
+ class String
14
+ include Relish::StringExtensions
15
+ end
@@ -1,10 +1,10 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "relish"
3
- s.version = "0.0.9"
3
+ s.version = "0.1.0"
4
4
 
5
5
  s.required_rubygems_version = '>= 1.3.5'
6
6
  s.authors = ["Matt Wynne", "Justin Ko"]
7
- s.date = "2010-09-23"
7
+ s.date = "2010-11-13"
8
8
  s.description = %q{Client gem for http://relishapp.com}
9
9
  s.email = "jko170@gmail.com"
10
10
 
@@ -4,16 +4,8 @@ module Relish
4
4
  module Command
5
5
  describe Config do
6
6
 
7
- describe '#default' do
8
- let(:config) { described_class.new }
9
-
10
- it 'calls #show' do
11
- config.should_receive(:show)
12
- config.default
13
- end
14
- end
15
7
 
16
- describe '#show' do
8
+ describe '#default' do
17
9
  let(:config) { described_class.new }
18
10
 
19
11
  context 'with a local options file' do
@@ -24,14 +16,14 @@ module Relish
24
16
 
25
17
  it 'outputs the contents' do
26
18
  config.should_receive(:puts).with('options')
27
- config.show
19
+ config.default
28
20
  end
29
21
  end
30
22
 
31
23
  context 'without a local options file' do
32
24
  it 'outputs the correct message' do
33
25
  config.should_receive(:puts).with('No .relish file exists')
34
- config.show
26
+ config.default
35
27
  end
36
28
  end
37
29
  end
@@ -5,6 +5,8 @@ module Relish
5
5
  module Dsl
6
6
  describe Command do
7
7
 
8
+ it_should_behave_like 'a Dsl that utilizes ContextClass'
9
+
8
10
  describe '#define' do
9
11
  let(:context_class) { Class.new }
10
12
  let(:command) { described_class.new(context_class) }
@@ -5,6 +5,8 @@ module Relish
5
5
  module Dsl
6
6
  describe Option do
7
7
 
8
+ it_should_behave_like 'a Dsl that utilizes ContextClass'
9
+
8
10
  describe '#define' do
9
11
  let(:context_class) { Class.new }
10
12
  let(:option) { described_class.new(context_class) }
@@ -2,17 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  module Relish
4
4
  module Command
5
- describe Projects do
6
-
7
- describe '#default' do
8
- let(:projects) { described_class.new }
9
-
10
- it 'calls #list' do
11
- projects.should_receive(:list)
12
- projects.default
13
- end
14
- end
15
-
16
- end
5
+
17
6
  end
18
7
  end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe String do
4
+ describe '#extract_option' do
5
+ specify { 'foo:bar'.extract_option.should eq('bar') }
6
+ end
7
+
8
+ describe '#remove_option' do
9
+ specify { 'foo:bar'.remove_option.should eq('foo') }
10
+ end
11
+ end
@@ -4,7 +4,8 @@ Bundler.setup
4
4
 
5
5
  require 'relish/command'
6
6
 
7
+ Dir['./spec/support/*.rb'].map {|f| require f }
8
+
7
9
  RSpec.configure do |config|
8
10
  config.color_enabled = true
9
-
10
11
  end
@@ -0,0 +1,24 @@
1
+ shared_examples_for 'a Dsl that utilizes ContextClass' do
2
+
3
+ describe '#context_class_eval' do
4
+ let(:context_class) { Class.new }
5
+ let(:base) { described_class.new(context_class) }
6
+ let(:the_block) { Proc.new { "Hi, I'm a block" } }
7
+
8
+ it 'calls class_eval on the context_class with the given block' do
9
+ context_class.should_receive(:class_eval).with(&the_block)
10
+ base.context_class_eval(&the_block)
11
+ end
12
+ end
13
+
14
+ describe '#context_class_name' do
15
+ let(:context_class) { Class.new }
16
+ let(:base) { described_class.new(context_class) }
17
+ before { context_class.should_receive(:name).and_return('::Dog') }
18
+
19
+ it 'returns the class name downcased' do
20
+ base.context_class_name.should eq('dog')
21
+ end
22
+ end
23
+
24
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relish
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
+ - 1
8
9
  - 0
9
- - 9
10
- version: 0.0.9
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matt Wynne
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-09-23 00:00:00 -06:00
19
+ date: 2010-11-13 00:00:00 -07:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -189,15 +189,17 @@ files:
189
189
  - lib/relish.rb
190
190
  - lib/relish/command.rb
191
191
  - lib/relish/commands/base.rb
192
+ - lib/relish/commands/collab.rb
192
193
  - lib/relish/commands/config.rb
193
194
  - lib/relish/commands/dsl.rb
194
- - lib/relish/commands/dsl/base.rb
195
195
  - lib/relish/commands/dsl/command.rb
196
+ - lib/relish/commands/dsl/context_class.rb
196
197
  - lib/relish/commands/dsl/help_text.rb
197
198
  - lib/relish/commands/dsl/option.rb
198
199
  - lib/relish/commands/help.rb
199
200
  - lib/relish/commands/projects.rb
200
201
  - lib/relish/commands/push.rb
202
+ - lib/relish/core_ext.rb
201
203
  - lib/relish/helpers.rb
202
204
  - lib/relish/options_file.rb
203
205
  - lib/relish/ui.rb
@@ -205,15 +207,16 @@ files:
205
207
  - spec/relish/command_spec.rb
206
208
  - spec/relish/commands/base_spec.rb
207
209
  - spec/relish/commands/config_spec.rb
208
- - spec/relish/commands/dsl/base_spec.rb
209
210
  - spec/relish/commands/dsl/command_spec.rb
210
211
  - spec/relish/commands/dsl/help_text_spec.rb
211
212
  - spec/relish/commands/dsl/option_spec.rb
212
213
  - spec/relish/commands/projects_spec.rb
213
214
  - spec/relish/commands/push_spec.rb
215
+ - spec/relish/core_ext_spec.rb
214
216
  - spec/relish/options_file_spec.rb
215
217
  - spec/relish_spec.rb
216
218
  - spec/spec_helper.rb
219
+ - spec/support/context_class_examples.rb
217
220
  has_rdoc: true
218
221
  homepage: http://relishapp.com
219
222
  licenses: []
@@ -261,12 +264,13 @@ test_files:
261
264
  - spec/relish/command_spec.rb
262
265
  - spec/relish/commands/base_spec.rb
263
266
  - spec/relish/commands/config_spec.rb
264
- - spec/relish/commands/dsl/base_spec.rb
265
267
  - spec/relish/commands/dsl/command_spec.rb
266
268
  - spec/relish/commands/dsl/help_text_spec.rb
267
269
  - spec/relish/commands/dsl/option_spec.rb
268
270
  - spec/relish/commands/projects_spec.rb
269
271
  - spec/relish/commands/push_spec.rb
272
+ - spec/relish/core_ext_spec.rb
270
273
  - spec/relish/options_file_spec.rb
271
274
  - spec/relish_spec.rb
272
275
  - spec/spec_helper.rb
276
+ - spec/support/context_class_examples.rb
@@ -1,23 +0,0 @@
1
- module Relish
2
- module Command
3
- module Dsl
4
- class Base
5
-
6
- attr_reader :context
7
-
8
- def initialize(context)
9
- @context = context
10
- end
11
-
12
- def context_eval(&block)
13
- context.class_eval(&block)
14
- end
15
-
16
- def context_name
17
- context.name.split('::').last.downcase
18
- end
19
-
20
- end
21
- end
22
- end
23
- end
@@ -1,32 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Relish
4
- module Command
5
- module Dsl
6
- describe Base do
7
-
8
- describe '#context_eval' do
9
- let(:context_class) { Class.new }
10
- let(:base) { described_class.new(context_class) }
11
- let(:the_block) { Proc.new { "Hi, I'm a block" } }
12
-
13
- it 'calls class_eval on the context_class with the given block' do
14
- context_class.should_receive(:class_eval).with(&the_block)
15
- base.context_eval(&the_block)
16
- end
17
- end
18
-
19
- describe '#context_name' do
20
- let(:context_class) { Class.new }
21
- let(:base) { described_class.new(context_class) }
22
- before { context_class.should_receive(:name).and_return('::Dog') }
23
-
24
- it 'returns the class name downcased' do
25
- base.context_name.should eq('dog')
26
- end
27
- end
28
-
29
- end
30
- end
31
- end
32
- end