marlene 0.1.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/.gitignore +5 -0
- data/README.markdown +17 -0
- data/Rakefile +19 -0
- data/bin/bm.pl +33 -0
- data/bin/marlene +112 -0
- data/lib/marlene.rb +60 -0
- data/lib/templates/loader.js +6 -0
- data/lib/templates/page.html +10 -0
- data/spec/marlene_spec.rb +105 -0
- metadata +107 -0
data/.gitignore
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Marlene - A bookmarklet builder
|
2
|
+
===============================
|
3
|
+
|
4
|
+
Marlene is inspired by John Grubers Perl based [JavaScript Bookmarklet Builder](http://daringfireball.net/2007/03/javascript_bookmarklet_builder).
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
Specs
|
9
|
+
-----
|
10
|
+
|
11
|
+
run specs with
|
12
|
+
|
13
|
+
spec spec/marlene_spec.rb --format specdoc
|
14
|
+
|
15
|
+
or
|
16
|
+
|
17
|
+
autospec
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/lib/marlene.rb"
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'jeweler'
|
5
|
+
Jeweler::Tasks.new do |gemspec|
|
6
|
+
gemspec.name = "marlene"
|
7
|
+
gemspec.version = Marlene::VERSION
|
8
|
+
gemspec.summary = "Bookmarklet Generator from a local or remote JavaScript file"
|
9
|
+
gemspec.description = "Marlene generates bookmarklet files or bookmarklet-pages from existing local javascript files or from remote javascript files represented by a URL."
|
10
|
+
gemspec.email = "thomduerr@gmail.com"
|
11
|
+
gemspec.homepage = "http://github.com/thomd/marlene/"
|
12
|
+
gemspec.authors = ["Thomas Duerr"]
|
13
|
+
gemspec.add_dependency "yui-compressor", ">= 0.9.1"
|
14
|
+
gemspec.add_dependency "mustache", ">= 0.11.2"
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
19
|
+
end
|
data/bin/bm.pl
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env perl
|
2
|
+
#
|
3
|
+
# http://daringfireball.net/2007/03/javascript_bookmarklet_builder
|
4
|
+
|
5
|
+
use strict;
|
6
|
+
use warnings;
|
7
|
+
use URI::Escape qw(uri_escape_utf8);
|
8
|
+
use open IO => ":utf8", # UTF8 by default
|
9
|
+
":std"; # Apply to STDIN/STDOUT/STDERR
|
10
|
+
|
11
|
+
my $src = do { local $/; <> };
|
12
|
+
|
13
|
+
# Zap the first line if there's already a bookmarklet comment:
|
14
|
+
$src =~ s{^// ?javascript:.+\n}{};
|
15
|
+
my $bookmarklet = $src;
|
16
|
+
|
17
|
+
for ($bookmarklet) {
|
18
|
+
s{^\s*//.+\n}{}gm; # Kill comments.
|
19
|
+
s{\t}{ }gm; # Tabs to spaces
|
20
|
+
s{[ ]{2,}}{ }gm; # Space runs to one space
|
21
|
+
s{^\s+}{}gm; # Kill line-leading whitespace
|
22
|
+
s{\s+$}{}gm; # Kill line-ending whitespace
|
23
|
+
s{\n}{}gm; # Kill newlines
|
24
|
+
}
|
25
|
+
|
26
|
+
# Escape single- and double-quotes, spaces, control chars, unicode:
|
27
|
+
$bookmarklet = "javascript:" .
|
28
|
+
uri_escape_utf8($bookmarklet, qq('" \x00-\x1f\x7f-\xff));
|
29
|
+
|
30
|
+
print "// $bookmarklet\n" . $src;
|
31
|
+
|
32
|
+
# Put bookmarklet on clipboard:
|
33
|
+
`/bin/echo -n '$bookmarklet' | /usr/bin/pbcopy`;
|
data/bin/marlene
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'trollop'
|
5
|
+
require 'uri'
|
6
|
+
require 'net/http'
|
7
|
+
require File.dirname(__FILE__) + '/../lib/marlene.rb'
|
8
|
+
|
9
|
+
opts = Trollop::options do
|
10
|
+
version "Marlene 0.1 (c) 2010 Thomas Duerr"
|
11
|
+
banner <<-EOS
|
12
|
+
Marlene builds code for bookmarklets from a local or from a remote hoted javascript file.
|
13
|
+
|
14
|
+
Usage:
|
15
|
+
marlene [options] <input>
|
16
|
+
|
17
|
+
where <input> is a file path or an URI to a javascript file.
|
18
|
+
|
19
|
+
[options] are:
|
20
|
+
EOS
|
21
|
+
|
22
|
+
opt :file, "write bookmarklet to file. Otherwise output goes to clipboard (OSX only) and STDOUT", :default => false
|
23
|
+
opt :include, "include bookmarklet code on top of input file as a comment", :default => false
|
24
|
+
# opt :jslint, "analyse javascript code via jslint before", :default => false, :short => "-l"
|
25
|
+
opt :publish, "build html page for bookmarklet and open it in a browser.", :default => false
|
26
|
+
end
|
27
|
+
|
28
|
+
Trollop::die "need at least a javascript file-path or a valid URI as input" if ARGV.empty?
|
29
|
+
|
30
|
+
input = ARGV.to_s
|
31
|
+
|
32
|
+
uri = URI.extract(input, 'http')[0]
|
33
|
+
if uri.nil? then
|
34
|
+
|
35
|
+
#
|
36
|
+
# ===== local javascript ==========
|
37
|
+
#
|
38
|
+
|
39
|
+
# stop if file does not exist
|
40
|
+
Trollop::die "#{input} must exist" unless File.exist?(input) if input
|
41
|
+
|
42
|
+
# read javascript file
|
43
|
+
local_file = File.read(input)
|
44
|
+
|
45
|
+
# build bookmarklet
|
46
|
+
bookmarklet = local_file.compress.to_bookmarklet
|
47
|
+
|
48
|
+
# include bookmarklet code as comment on top of input file
|
49
|
+
if opts[:include]
|
50
|
+
|
51
|
+
# remove first line if there's already a bookmarklet comment and
|
52
|
+
input.gsub!(/^\/\/ javascript:.+\n\n/, '')
|
53
|
+
|
54
|
+
File.open(input, "w") do |f|
|
55
|
+
f.puts "// #{bookmarklet}\n\n#{local_file}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
else
|
60
|
+
|
61
|
+
#
|
62
|
+
# ===== remote javascript ==========
|
63
|
+
#
|
64
|
+
|
65
|
+
# stop if URIs HTTP status is not 200
|
66
|
+
def remote_file_exists?(url)
|
67
|
+
url = URI.parse(url)
|
68
|
+
Net::HTTP.start(url.host, url.port) do |http|
|
69
|
+
return http.head(url.request_uri).code == "200"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
Trollop::die "#{uri} must exist" unless remote_file_exists?(uri) if uri
|
73
|
+
|
74
|
+
# build bookmarklet loadscript
|
75
|
+
bookmarklet = uri.to_loader_script.compress.to_bookmarklet
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
#
|
81
|
+
# ===== output ==========
|
82
|
+
#
|
83
|
+
if opts[:file]
|
84
|
+
|
85
|
+
# write bookmarklet code to a file "filename.bookmarklet"
|
86
|
+
output = input.gsub(Regexp.new(File.extname(input)), ".bookmarklet")
|
87
|
+
File.open(output, "w").write(bookmarklet)
|
88
|
+
else
|
89
|
+
|
90
|
+
# copy bookmarklet code to clipboard (OSX only)
|
91
|
+
IO.popen('pbcopy', 'w').puts bookmarklet
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# generate and open html page with bookmarklet-link in order to drag'n'drop bookmarklet up to bookmarks-bar
|
96
|
+
if opts[:publish]
|
97
|
+
begin
|
98
|
+
require 'bcat'
|
99
|
+
IO.popen('bcat', 'w').puts bookmarklet.to_bookmarklet_page
|
100
|
+
rescue LoadError => e
|
101
|
+
puts "Error: Publishing requires bcat gem: http://rtomayko.github.com/bcat/"
|
102
|
+
exit 1
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# write to stdout
|
108
|
+
if !opts[:publish] && !opts[:file]
|
109
|
+
puts bookmarklet
|
110
|
+
end
|
111
|
+
|
112
|
+
|
data/lib/marlene.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "yui/compressor"
|
3
|
+
require "mustache"
|
4
|
+
|
5
|
+
|
6
|
+
module Marlene
|
7
|
+
|
8
|
+
VERSION = "0.1.1"
|
9
|
+
ANCHOR_TEXTNODE = "bookmarklet"
|
10
|
+
PSEUDOCOL = "javascript:"
|
11
|
+
LOADER_SCRIPT = File.join(File.dirname(__FILE__), 'templates', 'loader.js')
|
12
|
+
BOOKMARKLET_PAGE = File.join(File.dirname(__FILE__), 'templates', 'page.html')
|
13
|
+
|
14
|
+
def yui_compressor
|
15
|
+
YUI::JavaScriptCompressor.new(:munge => true)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
class String
|
22
|
+
include Marlene
|
23
|
+
|
24
|
+
# transform into bookmarklet
|
25
|
+
def to_bookmarklet
|
26
|
+
js = self.to_s
|
27
|
+
js.gsub!(/^ +/, '') # remove line-leading whitespace
|
28
|
+
js.gsub!(/ +$/, '') # remove line-ending whitespace
|
29
|
+
js.gsub!(/\t/, ' ') # replace tabs with spaces
|
30
|
+
js.gsub!(/ +/, ' ') # replace multiple spaces with a single space
|
31
|
+
js.gsub!(/^ *\/\/.+\n/, '') # remove comment lines starting with a double slash
|
32
|
+
js.gsub!(/\n/, '') # remove all newlines
|
33
|
+
js = URI.escape(js, %Q(''" )) # URI escape: single- and double-quotes, spaces
|
34
|
+
PSEUDOCOL + js # prefix with 'javascript:'
|
35
|
+
end
|
36
|
+
|
37
|
+
# use YUI compressor to minimize javascript code
|
38
|
+
def compress
|
39
|
+
yui_compressor.compress(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
# insert into loader script a javascript URL
|
43
|
+
def to_loader_script
|
44
|
+
Mustache.template_file = LOADER_SCRIPT
|
45
|
+
loader = Mustache.new
|
46
|
+
loader[:script] = self
|
47
|
+
loader.render
|
48
|
+
end
|
49
|
+
|
50
|
+
# insert bookmarklet into html code for drag-drop bookmarklet up to linkbar
|
51
|
+
def to_bookmarklet_page
|
52
|
+
Mustache.template_file = BOOKMARKLET_PAGE
|
53
|
+
page = Mustache.new
|
54
|
+
page[:bookmarklet] = self
|
55
|
+
page[:anchor] = ANCHOR_TEXTNODE
|
56
|
+
page.render
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "spec"
|
3
|
+
require File.dirname(__FILE__) + '/../lib/marlene.rb'
|
4
|
+
|
5
|
+
describe "Marlene bookmark generator" do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@remote_url = "http://example.com/this/is/a/remote/javascript.js"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should transform a local javascript file to a bookmarklet" do
|
12
|
+
input = javascript_local
|
13
|
+
output = bookmarklet_local
|
14
|
+
input.to_bookmarklet.should == output
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should transform and escape a local javascript file to a bookmarklet" do
|
18
|
+
input = javascript_local_unescaped
|
19
|
+
output = bookmarklet_local_escaped
|
20
|
+
input.to_bookmarklet.should == output
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should transform an external javascript into a bookmarklet loaderscript" do
|
24
|
+
input = @remote_url
|
25
|
+
output = bookmarklet_remote
|
26
|
+
input.to_loader_script.to_bookmarklet.should == output
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should compress javascript code with a javascript compressor" do
|
30
|
+
input = javascript_local
|
31
|
+
output = javascript_local_compressed
|
32
|
+
input.compress.should == output
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should transform a local javascript file to a compressed bookmarklet" do
|
36
|
+
input = javascript_local
|
37
|
+
output = bookmarklet_local_compressed
|
38
|
+
input.compress.to_bookmarklet.should == output
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should transform an external javascript into a compressed bookmarklet loaderscript" do
|
42
|
+
input = @remote_url
|
43
|
+
output = bookmarklet_remote_compressed
|
44
|
+
input.to_loader_script.compress.to_bookmarklet.should == output
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should write a html page with a bookmarklet link" do
|
48
|
+
input = javascript_local_compressed
|
49
|
+
output = html_page_compressed_bookmarklet
|
50
|
+
input.compress.to_bookmarklet.to_bookmarklet_page.should == output
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
# fixtures
|
56
|
+
|
57
|
+
def javascript_local
|
58
|
+
"// a contains method for arrays
|
59
|
+
Array.prototype.contains = function(item){
|
60
|
+
return this.indexOf(item) > -1;
|
61
|
+
}
|
62
|
+
|
63
|
+
alert([1,2,3,4,5].contains(4));"
|
64
|
+
end
|
65
|
+
|
66
|
+
def javascript_local_unescaped
|
67
|
+
%Q{console.info(indentString + methodName, '-> ', result, "(", new Date - startTime, 'ms', ")");}
|
68
|
+
end
|
69
|
+
|
70
|
+
def javascript_local_compressed
|
71
|
+
"Array.prototype.contains=function(a){return this.indexOf(a)>-1};alert([1,2,3,4,5].contains(4));"
|
72
|
+
end
|
73
|
+
|
74
|
+
def bookmarklet_local
|
75
|
+
"javascript:Array.prototype.contains%20=%20function(item){return%20this.indexOf(item)%20>%20-1;}alert([1,2,3,4,5].contains(4));"
|
76
|
+
end
|
77
|
+
|
78
|
+
def bookmarklet_local_escaped
|
79
|
+
%Q{javascript:console.info(indentString%20+%20methodName,%20%27->%20%27,%20result,%20%22(%22,%20new%20Date%20-%20startTime,%20%27ms%27,%20%22)%22);}
|
80
|
+
end
|
81
|
+
|
82
|
+
def bookmarklet_local_compressed
|
83
|
+
"javascript:Array.prototype.contains=function(a){return%20this.indexOf(a)>-1};alert([1,2,3,4,5].contains(4));"
|
84
|
+
end
|
85
|
+
|
86
|
+
def bookmarklet_remote
|
87
|
+
"javascript:(function(){var%20script%20=%20document.createElement(%27script%27);script.type%20=%20%27text/javascript%27;script.src%20=%20%27http://example.com/this/is/a/remote/javascript.js?%27%20+%20(new%20Date().getTime());document.getElementsByTagName(%27body%27)[0].appendChild(script);})()"
|
88
|
+
end
|
89
|
+
|
90
|
+
def bookmarklet_remote_compressed
|
91
|
+
"javascript:(function(){var%20a=document.createElement(%22script%22);a.type=%22text/javascript%22;a.src=%22http://example.com/this/is/a/remote/javascript.js?%22+(new%20Date().getTime());document.getElementsByTagName(%22body%22)[0].appendChild(a)})();"
|
92
|
+
end
|
93
|
+
|
94
|
+
def html_page_compressed_bookmarklet
|
95
|
+
%Q(<!DOCTYPE html>
|
96
|
+
<html>
|
97
|
+
<head>
|
98
|
+
<meta charset="utf-8" />
|
99
|
+
<title>bookmarklet</title>
|
100
|
+
</head>
|
101
|
+
<body>
|
102
|
+
<a href="javascript:Array.prototype.contains=function(b){return%20this.indexOf(b)>-1};alert([1,2,3,4,5].contains(4));">bookmarklet</a>
|
103
|
+
</body>
|
104
|
+
</html>)
|
105
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: marlene
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Thomas Duerr
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-09 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: yui-compressor
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 57
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 9
|
33
|
+
- 1
|
34
|
+
version: 0.9.1
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: mustache
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 55
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 11
|
49
|
+
- 2
|
50
|
+
version: 0.11.2
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
description: Marlene generates bookmarklet files or bookmarklet-pages from existing local javascript files or from remote javascript files represented by a URL.
|
54
|
+
email: thomduerr@gmail.com
|
55
|
+
executables:
|
56
|
+
- bm.pl
|
57
|
+
- marlene
|
58
|
+
extensions: []
|
59
|
+
|
60
|
+
extra_rdoc_files:
|
61
|
+
- README.markdown
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- README.markdown
|
65
|
+
- Rakefile
|
66
|
+
- bin/marlene
|
67
|
+
- lib/marlene.rb
|
68
|
+
- lib/templates/loader.js
|
69
|
+
- lib/templates/page.html
|
70
|
+
- spec/marlene_spec.rb
|
71
|
+
- bin/bm.pl
|
72
|
+
has_rdoc: true
|
73
|
+
homepage: http://github.com/thomd/marlene/
|
74
|
+
licenses: []
|
75
|
+
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options:
|
78
|
+
- --charset=UTF-8
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 3
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
hash: 3
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
requirements: []
|
100
|
+
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.3.7
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: Bookmarklet Generator from a local or remote JavaScript file
|
106
|
+
test_files:
|
107
|
+
- spec/marlene_spec.rb
|