pastis 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +15 -0
- data/bin/pastis +73 -0
- data/lib/pastis.rb +222 -0
- metadata +56 -0
data/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Copyright (c) 2007 Samuel Lebeau
|
|
2
|
+
|
|
3
|
+
This program is free software; you can redistribute it and/or modify
|
|
4
|
+
it under the terms of the GNU General Public License as published by
|
|
5
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
6
|
+
(at your option) any later version.
|
|
7
|
+
|
|
8
|
+
This program is distributed in the hope that it will be useful,
|
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
GNU General Public License for more details.
|
|
12
|
+
|
|
13
|
+
You should have received a copy of the GNU General Public License
|
|
14
|
+
along with this program; if not, write to the Free Software
|
|
15
|
+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
data/bin/pastis
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
require 'pastis'
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
require 'optparse'
|
|
6
|
+
require 'timeout'
|
|
7
|
+
|
|
8
|
+
language = restricted = edit = nil
|
|
9
|
+
|
|
10
|
+
def version
|
|
11
|
+
"Pastis, version #{Pastis::Version.join('.')}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
OptionParser.new do |opts|
|
|
15
|
+
opts.banner = <<END
|
|
16
|
+
#{version}
|
|
17
|
+
Paste the given file or STDIN to Pastie, returns the paste URL.
|
|
18
|
+
|
|
19
|
+
Usage: #{ARGV.first} [options] [file]
|
|
20
|
+
END
|
|
21
|
+
|
|
22
|
+
opts.separator ''
|
|
23
|
+
|
|
24
|
+
opts.separator 'Options:'
|
|
25
|
+
|
|
26
|
+
opts.on('-l', '--language [LANGUAGE]', "Select a language\n\
|
|
27
|
+
(c/diff/html/javascript/nitro_xhtml/pascal/plaintext/rhtml/ruby/sql)") do |l|
|
|
28
|
+
language = l.downcase
|
|
29
|
+
end
|
|
30
|
+
opts.on('-p', '--[no-]private', 'Private paste (default to false)') { |r| restricted = r }
|
|
31
|
+
opts.on('-e', '--[no-]edit', 'Edit the input with $EDITOR (defaults to false)') { |e| edit = e }
|
|
32
|
+
|
|
33
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
|
34
|
+
puts opts
|
|
35
|
+
exit
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
opts.on_tail('-v', '--version', 'Print Pastis version') do
|
|
39
|
+
puts version
|
|
40
|
+
exit
|
|
41
|
+
end
|
|
42
|
+
end.parse!
|
|
43
|
+
|
|
44
|
+
paste =
|
|
45
|
+
if ARGV.first
|
|
46
|
+
File.read(ARGV.first)
|
|
47
|
+
else
|
|
48
|
+
# detect if there's something from STDIN
|
|
49
|
+
begin
|
|
50
|
+
timeout(0.1) { $stdin.gets } << $stdin.read
|
|
51
|
+
rescue TimeoutError
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
if (!paste || edit)
|
|
56
|
+
Tempfile.open('pastie') do |f|
|
|
57
|
+
f << paste
|
|
58
|
+
f.rewind
|
|
59
|
+
system("#{ENV['EDITOR']} #{f.path}")
|
|
60
|
+
f.rewind
|
|
61
|
+
# Tempfile.open curiously returns 'nil' instead of the last expression
|
|
62
|
+
paste = f.read
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
begin
|
|
67
|
+
puts Pastis.paste(paste, {
|
|
68
|
+
:language => language,
|
|
69
|
+
:private => restricted
|
|
70
|
+
}).url
|
|
71
|
+
rescue Pastis::Error => e
|
|
72
|
+
abort e.message
|
|
73
|
+
end
|
data/lib/pastis.rb
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'open-uri'
|
|
3
|
+
|
|
4
|
+
# Load Hpricot on demand
|
|
5
|
+
def Hpricot(object) #:nodoc:
|
|
6
|
+
require 'rubygems'
|
|
7
|
+
require 'hpricot'
|
|
8
|
+
Kernel.send(:Hpricot, object)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Module #:nodoc:
|
|
12
|
+
alias_method :const_missing_without_pastis, :const_missing
|
|
13
|
+
|
|
14
|
+
# Load CGI on demand
|
|
15
|
+
def const_missing(const)
|
|
16
|
+
if const == :CGI
|
|
17
|
+
require 'cgi'
|
|
18
|
+
Module.send(:alias_method, :const_missing, :const_missing_without_pastis)
|
|
19
|
+
CGI
|
|
20
|
+
else
|
|
21
|
+
const_missing_without_pastis(const)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# Pastis is a simple ruby interface to Pastie (http://pastie.caboo.se)
|
|
28
|
+
#
|
|
29
|
+
# == Usage
|
|
30
|
+
#
|
|
31
|
+
# paste = Pastis.paste "var some = 'private js code';", :language => :javascript, :private => true
|
|
32
|
+
#
|
|
33
|
+
# paste.url
|
|
34
|
+
# # => "http://pastie.caboo.se/private/lbejcc0royyyyozwl8jbg"
|
|
35
|
+
#
|
|
36
|
+
# paste.raw_url
|
|
37
|
+
# # => "http://pastie.caboo.se/private/lbejcc0royyyyozwl8jbg.txt"
|
|
38
|
+
#
|
|
39
|
+
# paste.body
|
|
40
|
+
# # => "var some = 'private js code';"
|
|
41
|
+
#
|
|
42
|
+
# pages = Pastis.search [a search expression]
|
|
43
|
+
#
|
|
44
|
+
# pages.next_page.last.url
|
|
45
|
+
# # => "http://pastie.caboo.se/pastes/43577"
|
|
46
|
+
module Pastis
|
|
47
|
+
Version = [ 0, 0, 1 ]
|
|
48
|
+
|
|
49
|
+
class Error < RuntimeError; end
|
|
50
|
+
class PasteNotCreatedError < Error; end
|
|
51
|
+
class EmptyPasteError < Error; end
|
|
52
|
+
class PaginationError < Error; end
|
|
53
|
+
|
|
54
|
+
# Represents a paste, shoudn't be created by hand
|
|
55
|
+
class Paste
|
|
56
|
+
def initialize(attributes)
|
|
57
|
+
%w(url body time preview).each do |attribute|
|
|
58
|
+
instance_variable_set("@#{attribute}", attributes[attribute.intern])
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
attr_reader :url
|
|
63
|
+
|
|
64
|
+
# Url of the raw paste
|
|
65
|
+
def raw_url
|
|
66
|
+
"#{url}.txt"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# 5 first lines of the paste
|
|
70
|
+
def preview
|
|
71
|
+
@preview ||= body.to_a[0, 6].to_s
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Creation time
|
|
75
|
+
def time
|
|
76
|
+
@time ||= Time.parse(Hpricot(get(url)).at("#paste_date").innerText)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Body of the paste
|
|
80
|
+
def body
|
|
81
|
+
@body ||= get(raw_url)
|
|
82
|
+
end
|
|
83
|
+
alias_method :to_s, :body
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def get(url)
|
|
88
|
+
Pastis.send(:get, url)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Represents a collection of pastes paginated
|
|
93
|
+
class Collection < Array
|
|
94
|
+
def initialize(page, &block)
|
|
95
|
+
@page, @block = page, block
|
|
96
|
+
|
|
97
|
+
parse_url(yield(page))
|
|
98
|
+
super(@pastes)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
attr_reader :page, :pages_count
|
|
102
|
+
|
|
103
|
+
def next_page
|
|
104
|
+
raise PaginationError, "last page" if last_page?
|
|
105
|
+
move(page + 1)
|
|
106
|
+
end
|
|
107
|
+
alias_method :next, :next_page
|
|
108
|
+
|
|
109
|
+
def previous_page
|
|
110
|
+
raise PaginationError, "first page" if first_page?
|
|
111
|
+
move(page - 1)
|
|
112
|
+
end
|
|
113
|
+
alias_method :previous, :previous_page
|
|
114
|
+
|
|
115
|
+
def goto_page(page)
|
|
116
|
+
raise PaginationError, "page out of range" unless (1..pages_count).member?(page)
|
|
117
|
+
move(page)
|
|
118
|
+
end
|
|
119
|
+
alias_method :goto, :goto_page
|
|
120
|
+
|
|
121
|
+
def last_page?
|
|
122
|
+
page == pages_count
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def first_page?
|
|
126
|
+
page == 1
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def get(url)
|
|
132
|
+
Pastis.send(:get, url)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def move(page)
|
|
136
|
+
Collection.new(page, &@block)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def parse_url(url)
|
|
140
|
+
doc = Hpricot(get(url))
|
|
141
|
+
|
|
142
|
+
@pastes = (doc/'.pastePreview').collect do |node|
|
|
143
|
+
Paste.new :time => Time.parse(node.at('.when span').innerText),
|
|
144
|
+
:url => node.at('.link a').attributes['href'],
|
|
145
|
+
:preview => node.at('.code').innerText
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
@pages_count =
|
|
149
|
+
Hpricot((doc/'.pages strong').first.innerText.split(' ').last).innerText.to_i
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
class << self
|
|
154
|
+
def url #:nodoc:
|
|
155
|
+
"http://pastie.caboo.se"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Creates a paste, returns the created Paste object.
|
|
159
|
+
# The options are :
|
|
160
|
+
#
|
|
161
|
+
# * <tt>:language</tt>: The language used in the paste (defaults to Ruby)
|
|
162
|
+
# * <tt>:private</tt>: true if the paste is private (default to false)
|
|
163
|
+
def create(body, options = {})
|
|
164
|
+
raise EmptyPasteError, "Empty paste, not submitted..." unless body =~ /\w/
|
|
165
|
+
|
|
166
|
+
response = post_paste(body, options);
|
|
167
|
+
|
|
168
|
+
raise PasteNotCreatedError, "Error occured : #{response.code}" unless response.code =~ /[23]0\d/
|
|
169
|
+
raise PasteNotCreatedError, "Paste not created" unless response['location']
|
|
170
|
+
|
|
171
|
+
return Paste.new(:body => body, :url => response['location'], :time => Time.now)
|
|
172
|
+
end
|
|
173
|
+
alias_method :paste, :create
|
|
174
|
+
|
|
175
|
+
# Searches some expression on Pastie.
|
|
176
|
+
# Returns a Collection object
|
|
177
|
+
def search(expression, page = 1)
|
|
178
|
+
Collection.new(page) do |page|
|
|
179
|
+
search_url(expression, page)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Lists all pastes.
|
|
184
|
+
# Returns a Collection object
|
|
185
|
+
def list(page = 1)
|
|
186
|
+
Collection.new(page) do |page|
|
|
187
|
+
all_url(page)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
alias_method :all, :list
|
|
191
|
+
|
|
192
|
+
private
|
|
193
|
+
|
|
194
|
+
def post_paste(body, options)
|
|
195
|
+
post(create_url,
|
|
196
|
+
"paste[restricted]" => options[:private] ? '1' : '0',
|
|
197
|
+
"paste[parser]" => options[:language] ? options[:language].to_s.downcase : :ruby,
|
|
198
|
+
"paste[body]" => body,
|
|
199
|
+
"paste[authorization]" => 'burger');
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def get(url)
|
|
203
|
+
open(url) { |f| f.read }
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def post(url, parameters = {})
|
|
207
|
+
Net::HTTP.post_form(URI.parse(url), parameters)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def create_url
|
|
211
|
+
"#{url}/pastes/create"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def search_url(query, page)
|
|
215
|
+
"#{url}/search?q=#{CGI.escape(query.to_s)}&page=#{page}"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def all_url(page)
|
|
219
|
+
"#{url}/all/page/#{page}"
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
rubygems_version: 0.9.4
|
|
3
|
+
specification_version: 1
|
|
4
|
+
name: pastis
|
|
5
|
+
version: !ruby/object:Gem::Version
|
|
6
|
+
version: 0.0.1
|
|
7
|
+
date: 2007-09-25 00:00:00 +02:00
|
|
8
|
+
summary: A simple interface to Pastie
|
|
9
|
+
require_paths:
|
|
10
|
+
- lib
|
|
11
|
+
email: sam@gotfresh.info
|
|
12
|
+
homepage: http://i.gotfresh.info
|
|
13
|
+
rubyforge_project:
|
|
14
|
+
description: Pastis is a simple interface to create, list and search for pastes on Pastie (http://pastie.caboo.se).\n\ It could be used as a library or a standalone binary
|
|
15
|
+
autorequire:
|
|
16
|
+
default_executable:
|
|
17
|
+
bindir: bin
|
|
18
|
+
has_rdoc: true
|
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">"
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: 0.0.0
|
|
24
|
+
version:
|
|
25
|
+
platform: ruby
|
|
26
|
+
signing_key:
|
|
27
|
+
cert_chain:
|
|
28
|
+
post_install_message:
|
|
29
|
+
authors:
|
|
30
|
+
- Samuel Lebeau
|
|
31
|
+
files:
|
|
32
|
+
- LICENSE
|
|
33
|
+
- bin/pastis
|
|
34
|
+
- lib/pastis.rb
|
|
35
|
+
test_files: []
|
|
36
|
+
|
|
37
|
+
rdoc_options: []
|
|
38
|
+
|
|
39
|
+
extra_rdoc_files: []
|
|
40
|
+
|
|
41
|
+
executables:
|
|
42
|
+
- pastis
|
|
43
|
+
extensions: []
|
|
44
|
+
|
|
45
|
+
requirements: []
|
|
46
|
+
|
|
47
|
+
dependencies:
|
|
48
|
+
- !ruby/object:Gem::Dependency
|
|
49
|
+
name: hpricot
|
|
50
|
+
version_requirement:
|
|
51
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: "0.6"
|
|
56
|
+
version:
|