marlene 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ bin/bm.pl
2
+ test*.js
3
+ TODO.markdown
4
+ *.bookmarklet
5
+ pkg
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,6 @@
1
+ (function(){
2
+ var script = document.createElement('script');
3
+ script.type = 'text/javascript';
4
+ script.src = '{{script}}?' + (new Date().getTime());
5
+ document.getElementsByTagName('body')[0].appendChild(script);
6
+ })()
@@ -0,0 +1,10 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>{{anchor}}</title>
6
+ </head>
7
+ <body>
8
+ <a href="{{{bookmarklet}}}">{{anchor}}</a>
9
+ </body>
10
+ </html>
@@ -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