nwcopy 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ tmp/*
data/Gemfile.lock ADDED
@@ -0,0 +1,21 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nwcopy (0.0.4)
5
+ sinatra
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ rack (1.2.1)
11
+ sinatra (1.1.2)
12
+ rack (~> 1.1)
13
+ tilt (~> 1.2)
14
+ tilt (1.2.2)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ nwcopy!
21
+ sinatra
data/lib/nwcopy.rb CHANGED
@@ -2,39 +2,54 @@ $:.unshift(File.dirname(__FILE__)) unless
2
2
  $:.include?(File.dirname(__FILE__)) ||
3
3
  $:.include?(File.expand_path(File.dirname(__FILE__)))
4
4
 
5
+ require 'nwcopy/client'
5
6
  require 'nwcopy/dropbox'
7
+ require 'nwcopy/gist'
6
8
 
7
9
  module Nwcopy
10
+
11
+ def self.plugins
12
+ [Nwcopy::Client, Nwcopy::Dropbox, Nwcopy::Gist]
13
+ end
14
+
8
15
  def self.copy
9
16
  data = read_data
10
- if Nwcopy::Dropbox.available?
11
- Nwcopy::Dropbox.copy data
12
- else
13
- STDERR << NwCopy::Dropbox.unavailable_message
17
+ unavailable = []
18
+ plugins.each do |plugin|
19
+ if plugin.available?
20
+ return plugin.copy data
21
+ else
22
+ unavailable << plugin.unavailable_message
23
+ end
14
24
  end
25
+ STDERR << unavailable.join("\n")
15
26
  end
16
27
 
17
28
  def self.paste
18
- if Nwcopy::Dropbox.available?
19
- if clipboard = Nwcopy::Dropbox.paste
20
- `echo "#{clipboard}" | pbcopy` unless `which pbcopy`.empty?
21
- clipboard
29
+ unavailable = []
30
+ plugins.each do |plugin|
31
+ if plugin.available?
32
+ if clipboard = plugin.paste
33
+ `echo "#{clipboard}" | pbcopy` unless `which pbcopy`.empty?
34
+ return clipboard
35
+ end
36
+ else
37
+ unavailable << plugin.unavailable_message
22
38
  end
23
- else
24
- STDERR << NwCopy::Dropbox.unavailable_message
25
39
  end
40
+ STDERR << unavailable.join("\n")
26
41
  end
27
42
 
28
43
  private
29
44
  def self.read_data
30
45
  if ARGF.file == STDIN
31
- STDIN.read_nonblock(1) + STDIN.read
46
+ StringIO.new(STDIN.read_nonblock(1) + STDIN.read)
32
47
  else
33
- ARGF.read
48
+ ARGF
34
49
  end
35
50
  rescue IO::WaitReadable => e
36
51
  unless `which pbpaste`.empty?
37
- `pbpaste`
52
+ StringIO.new(`pbpaste`)
38
53
  else
39
54
  STDERR << 'Nothing to do!'
40
55
  end
@@ -0,0 +1,82 @@
1
+ require 'net/http/post/multipart'
2
+ require 'tempfile'
3
+ require 'json'
4
+
5
+ module Nwcopy
6
+ class Client
7
+ class << self
8
+ attr_writer :gist
9
+ end
10
+
11
+ def self.unavailable_message
12
+ "nwcopy is not configured. Go to nwcopy.heroku.com. Then set $NWCOPY_CREDS."
13
+ end
14
+
15
+ def self.available?
16
+ ENV['NWCOPY_CREDS']
17
+ end
18
+
19
+ def self.time
20
+ Time.now
21
+ end
22
+
23
+ def self.copy data
24
+ if data.respond_to? :filename
25
+ filename = data.filename
26
+ else
27
+ filename = nil
28
+ @tmpfile = Tempfile.new 'nwcopy'
29
+ @tmpfile.write(data.read)
30
+ @tmpfile.close
31
+ data = File.open @tmpfile.path
32
+ end
33
+
34
+ io = UploadIO.new(data, nil, filename)
35
+
36
+ url = URI.parse("#{base_url}/copy")
37
+ req = Net::HTTP::Post::Multipart.new url.path, 'data' => io
38
+ res = start req, url
39
+
40
+ res.body
41
+ ensure
42
+ @tmpfile.unlink if @tmpfile
43
+ @tmpfile = nil
44
+ end
45
+
46
+
47
+ def self.paste
48
+ url = URI.parse("#{base_url}/paste")
49
+
50
+ req = Net::HTTP::Get.new(url.path)
51
+ res = start req, url
52
+
53
+ file = res['Location'] ? res['Location'].split('/').last : nil
54
+
55
+ if file && !File.exists?(file)
56
+ File.open file, 'w+' do |f|
57
+ f << res.body
58
+ end
59
+ "Pasted to #{file}"
60
+ else
61
+ res.body
62
+ end
63
+ end
64
+
65
+ private
66
+ def self.start req, url
67
+ req.basic_auth *credentials
68
+ Net::HTTP.start(url.host, url.port) do |http|
69
+ http.request req
70
+ end
71
+ end
72
+
73
+ def self.base_url
74
+ ENV['NWCOPY_TEST'] == 'true' ? 'http://localhost:3000' : 'http://nwcopy.heroku.com'
75
+ end
76
+
77
+ def self.credentials
78
+ ENV['NWCOPY_CREDS'].split(':')
79
+ end
80
+
81
+ end
82
+ end
@@ -2,6 +2,10 @@ require 'digest/sha1'
2
2
 
3
3
  module Nwcopy
4
4
  class Dropbox
5
+ class << self
6
+ attr_accessor :dropbox_base
7
+ end
8
+
5
9
  def self.unavailable_message
6
10
  "Dropbox was not found at #{nwcopy_dir}. Get it at http://getdropbox.com/"
7
11
  end
@@ -10,14 +14,14 @@ module Nwcopy
10
14
  return false unless File.exists? dropbox_dir
11
15
 
12
16
  unless File.exists? nwcopy_dir
13
- STDERR << "Creating nwcopy directory at #{nwcopy_dir}"
14
17
  Dir.mkdir nwcopy_dir
15
18
  end
16
19
 
17
20
  File.exists? nwcopy_dir
18
21
  end
19
22
 
20
- def self.copy clipboard
23
+ def self.copy io
24
+ clipboard = io.read
21
25
  digest = Digest::SHA1.hexdigest clipboard
22
26
  nwcopy_file = File.join nwcopy_dir, digest
23
27
  File.open(nwcopy_file, 'w+') do |f|
@@ -28,7 +32,7 @@ module Nwcopy
28
32
 
29
33
  # Used to determine which plugin has the newest file.
30
34
  def self.time
31
- latest_file.mtime
35
+ latest_file ? latest_file.mtime : nil
32
36
  end
33
37
 
34
38
  def self.paste
@@ -50,7 +54,7 @@ module Nwcopy
50
54
  end
51
55
 
52
56
  def self.dropbox_dir
53
- File.expand_path '~/Dropbox'
57
+ File.expand_path(dropbox_base || '~/Dropbox')
54
58
  end
55
59
 
56
60
  def self.nwcopy_dir
@@ -0,0 +1,50 @@
1
+ require 'gist'
2
+ require 'tempfile'
3
+ require 'digest/sha1'
4
+ require 'json'
5
+
6
+ module Nwcopy
7
+ class Gist
8
+ class << self
9
+ attr_writer :gist
10
+ end
11
+
12
+ def self.unavailable_message
13
+ "Github is not configured. Cannot use Gist."
14
+ end
15
+
16
+ def self.available?
17
+ !gist.send(:auth).empty?
18
+ end
19
+
20
+ def self.time
21
+ Time.parse(latest_gist["created_at"])
22
+ end
23
+
24
+ def self.copy io
25
+ clipboard = io.read
26
+ digest = Digest::SHA1.hexdigest clipboard
27
+ filename = io.respond_to?(:filename) ? io.filename : digest
28
+ gist.write [{:filename => filename, :input => clipboard}], false
29
+ end
30
+
31
+ def self.paste
32
+ gist.read latest_gist["repo"]
33
+ end
34
+
35
+ private
36
+ def self.latest_gist
37
+ gist.list["gists"].sort{|x, y| Time.parse(y["created_at"]) <=> Time.parse(x["created_at"])}.first
38
+ end
39
+
40
+ def self.gist
41
+ @gist || ::Gist
42
+ end
43
+ end
44
+ end
45
+
46
+ module ::Gist
47
+ def self.list
48
+ JSON.parse open("http://gist.github.com/api/v1/json/gists/#{config('github.user')}").read
49
+ end
50
+ end
@@ -1,3 +1,3 @@
1
1
  module Nwcopy
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
data/nwcopy.gemspec CHANGED
@@ -12,8 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.summary = %q{network copy & paste.}
13
13
  s.description = %q{Uses your Dropbox folder to facilitate copy and pasting between machines. More awesomesauce to come.}
14
14
 
15
- s.rubyforge_project = "nwcopy"
16
-
15
+ s.add_dependency 'sinatra'
17
16
  s.files = `git ls-files`.split("\n")
18
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -0,0 +1,85 @@
1
+ require 'test_helper'
2
+ require 'fileutils'
3
+
4
+ describe Nwcopy::Dropbox do
5
+ before do
6
+ @dropbox = Nwcopy::Dropbox
7
+ @base = File.expand_path(File.join(File.dirname(__FILE__), '..', 'tmp', 'Dropbox'))
8
+ @nwcopy_base = File.join(@base, 'nwcopy')
9
+ @dropbox.dropbox_base = @base
10
+ end
11
+
12
+ describe :with_dropbox do
13
+ before do
14
+ @dropbox.dropbox_base = @base
15
+ FileUtils.mkdir_p @base
16
+ @available = @dropbox.available?
17
+ end
18
+
19
+ describe :available? do
20
+
21
+ it "should respond positively" do
22
+ @available.must_equal true
23
+ end
24
+
25
+ it "should create an nwcopy directory" do
26
+ File.exists?(@nwcopy_base).must_equal true
27
+ end
28
+
29
+ end
30
+
31
+ describe :time do
32
+ before do
33
+ @testfile = File.join(@nwcopy_base, 'foobar')
34
+ end
35
+
36
+ it "should return nil when no files exist" do
37
+ @dropbox.time.must_be_nil
38
+ end
39
+
40
+ it "should return the time when files exist" do
41
+ FileUtils.touch(@testfile)
42
+ @dropbox.time.must_equal File.new(@testfile).mtime
43
+ end
44
+ end
45
+
46
+ describe :copy do
47
+ before do
48
+ @data = "Bad artists copy. Good artists steal."
49
+ @file = @dropbox.copy StringIO.new(@data)
50
+ end
51
+
52
+ it "should exist" do
53
+ File.exists?(@file).must_equal true
54
+ end
55
+
56
+ it "should have the same data" do
57
+ File.new(@file).read.must_equal @data
58
+ end
59
+ end
60
+
61
+ describe :paste do
62
+ before do
63
+ @data = "Copy from one, it's plagiarism; copy from two, it's research."
64
+ @file = @dropbox.copy StringIO.new(@data)
65
+ @pasted = @dropbox.paste
66
+ end
67
+
68
+ it "should match the original data" do
69
+ @data.must_equal @pasted
70
+ end
71
+ end
72
+
73
+ after do
74
+ FileUtils.rm_rf @base
75
+ end
76
+ end
77
+
78
+ describe :without_dropbox do
79
+ describe :available? do
80
+ it "should respond negatively" do
81
+ @dropbox.available?.must_equal false
82
+ end
83
+ end
84
+ end
85
+ end
data/test/test_gist.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'test_helper'
2
+
3
+ describe Nwcopy::Gist do
4
+
5
+ before do
6
+ @gist = Nwcopy::Gist
7
+ @gists = {"gists" => [
8
+ {"public" => true,"created_at" => "2010/11/11 15:20:55 -0800","owner" => "j05h","files" => ["distance.rb"],
9
+ "description" => "Haversine formula in ruby", "repo" => "673425"},
10
+ {"public" => true,"created_at" => "2010/09/28 12:26:29 -0700","owner" => "j05h","files" => ["random_string.rb"],
11
+ "description" => nil, "repo" => "601616"},
12
+ {"public" => true,"created_at" => "2010/07/09 15:01:22 -0700","owner" => "j05h","files" => ["gistfile1.rb"],
13
+ "description" => nil,"repo" => "470131"}]}
14
+ end
15
+
16
+ describe :with_github do
17
+ before do
18
+ @mock = MiniTest::Mock.new
19
+ @mock.expect :auth, {"foo" => "bar"}
20
+ @gist.gist = @mock
21
+ end
22
+
23
+ describe :available do
24
+ it 'should be' do
25
+ @gist.available?.must_equal true
26
+ end
27
+ end
28
+
29
+ describe :time do
30
+ before do
31
+ @mock.expect :list, @gists
32
+ end
33
+
34
+ it "should return the latest time" do
35
+ @gist.time.must_equal Time.parse(@gists["gists"].first["created_at"])
36
+ end
37
+ end
38
+
39
+ describe :copy do
40
+ before do
41
+ @mock.expect :write, "someurl", [String, true]
42
+ end
43
+
44
+ it "should return a url response" do
45
+ @gist.copy(StringIO.new("To all good things an end must come.")).must_equal "someurl"
46
+ end
47
+ end
48
+
49
+ describe :paste do
50
+ before do
51
+ @mock.expect :list, @gists
52
+ @mock.expect :read, "Wassup?", [@gists["gists"].first["repo"]]
53
+ end
54
+
55
+ it "should return appropriate data" do
56
+ @gist.paste.must_equal "Wassup?"
57
+ end
58
+ end
59
+ end
60
+
61
+
62
+ describe :without_github do
63
+ before do
64
+ @mock = MiniTest::Mock.new
65
+ @mock.expect :auth, {}
66
+ @gist.gist = @mock
67
+ end
68
+
69
+ describe :available do
70
+ it 'should not be' do
71
+ @gist.available?.must_equal false
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,3 @@
1
+ require 'nwcopy'
2
+ require 'minitest/spec'
3
+ require 'minitest/mock'
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nwcopy
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 0
9
- - 4
10
- version: 0.0.4
8
+ - 5
9
+ version: 0.0.5
11
10
  platform: ruby
12
11
  authors:
13
12
  - Josh Kleinpeter
@@ -15,10 +14,22 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-01-31 00:00:00 -06:00
17
+ date: 2011-02-05 00:00:00 -06:00
19
18
  default_executable:
20
- dependencies: []
21
-
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: sinatra
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
22
33
  description: Uses your Dropbox folder to facilitate copy and pasting between machines. More awesomesauce to come.
23
34
  email:
24
35
  - josh@kleinpeter.org
@@ -32,14 +43,20 @@ extra_rdoc_files: []
32
43
  files:
33
44
  - .gitignore
34
45
  - Gemfile
46
+ - Gemfile.lock
35
47
  - README.rdoc
36
48
  - Rakefile
37
49
  - bin/nwcopy
38
50
  - bin/nwpaste
39
51
  - lib/nwcopy.rb
52
+ - lib/nwcopy/client.rb
40
53
  - lib/nwcopy/dropbox.rb
54
+ - lib/nwcopy/gist.rb
41
55
  - lib/nwcopy/version.rb
42
56
  - nwcopy.gemspec
57
+ - test/test_dropbox.rb
58
+ - test/test_gist.rb
59
+ - test/test_helper.rb
43
60
  has_rdoc: true
44
61
  homepage: ""
45
62
  licenses: []
@@ -54,7 +71,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
54
71
  requirements:
55
72
  - - ">="
56
73
  - !ruby/object:Gem::Version
57
- hash: 3
58
74
  segments:
59
75
  - 0
60
76
  version: "0"
@@ -63,16 +79,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
79
  requirements:
64
80
  - - ">="
65
81
  - !ruby/object:Gem::Version
66
- hash: 3
67
82
  segments:
68
83
  - 0
69
84
  version: "0"
70
85
  requirements: []
71
86
 
72
- rubyforge_project: nwcopy
87
+ rubyforge_project:
73
88
  rubygems_version: 1.3.7
74
89
  signing_key:
75
90
  specification_version: 3
76
91
  summary: network copy & paste.
77
- test_files: []
78
-
92
+ test_files:
93
+ - test/test_dropbox.rb
94
+ - test/test_gist.rb
95
+ - test/test_helper.rb