juliocesar-harmony 0.5.2

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
+ *.gem
2
+ .yardoc/
3
+ doc/
4
+ TODO
5
+ .yard_issues.md
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright © 2009 Martin Aumont (mynyml)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,13 @@
1
+ .gitignore
2
+ LICENSE
3
+ Manifest
4
+ README.md
5
+ Rakefile
6
+ docs.watchr
7
+ harmony.gemspec
8
+ lib/harmony.rb
9
+ lib/harmony/page.rb
10
+ specs.watchr
11
+ test/harmony_test.rb
12
+ test/page_test.rb
13
+ test/test_helper.rb
data/README.md ADDED
@@ -0,0 +1,162 @@
1
+ Harmony
2
+ =======
3
+
4
+ .,ad88888888baa,
5
+ ,d8P""" ""9888ba.
6
+ .a8" ,ad88888888888a
7
+ aP' ,88888888888888888a
8
+ ,8" ,88888888888888888888,
9
+ ,8' (888888888( )888888888,
10
+ ,8' `8888888888888888888888
11
+ 8) `888888888888888888888,
12
+ 8 "8888888888888888888)
13
+ 8 `888888888888888888)
14
+ 8) "8888888888888888
15
+ (b "88888888888888'
16
+ `8, (8) 8888888888888)
17
+ "8a ,888888888888)
18
+ V8, d88888888888"
19
+ `8b, ,d8888888888P'
20
+ `V8a, ,ad8888888888P'
21
+ ""88888888888888888P"
22
+ """"""""""""
23
+
24
+ Summary
25
+ -------
26
+
27
+ Harmony provides a simple DSL to execute javascript + DOM code within ruby.
28
+
29
+ Examples
30
+ --------
31
+
32
+ ### Simple Javascript Parsing
33
+
34
+ require 'harmony'
35
+
36
+ page = Harmony::Page.new(<<-HTML)
37
+ <html>
38
+ <head>
39
+ <title>Foo</title>
40
+ </head>
41
+ <body></body>
42
+ </html>
43
+ HTML
44
+
45
+ page.execute_js("1+1") #=> 2
46
+ page.execute_js("document.title") #=> "Foo"
47
+
48
+ The Page object's `#execute_js` method (aliased as `#x` for convenience) takes a
49
+ string of javascript code, executes it and returns the last statement's value
50
+ (just like a ruby method).
51
+
52
+ ### Javascript Unit Tests
53
+
54
+ One interesting use of Harmony is to test your javascript code within your ruby
55
+ application's own tests (test/unit, minitest, RSpec, nanotest, etc). Which
56
+ consequently means that you can now run browser-less, fully command-line
57
+ based, DOM-javascript tests.
58
+
59
+ require 'test/unit'
60
+ require 'harmony'
61
+
62
+ class JavascriptTest < Test::Unit::TestCase
63
+ def setup
64
+ @page = Harmony::Page.new
65
+ @page.load('public/javascripts/foo.js')
66
+ end
67
+
68
+ def test_foo
69
+ assert_equal "world", @page.execute_js(<<-JS)
70
+ foo = new Foo;
71
+ foo.hello();
72
+ JS
73
+ end
74
+ end
75
+
76
+ ### DOM Handling
77
+
78
+ Don't be affraid to throw in your favorite client-side js framework, like
79
+ JQuery or Prototype. And notice that scripts linked to in `<script>` tags will
80
+ automatically get pulled in.
81
+
82
+ require 'harmony'
83
+
84
+ page = Harmony::Page.new(<<-HTML)
85
+ <html>
86
+ <head>
87
+ <script src="javascripts/jquery.js" type="text/javascript"></script>
88
+ </head>
89
+ <body>
90
+ <div id="widget">ohaie</div>
91
+ </body>
92
+ </html>
93
+ HTML
94
+
95
+ page.execute_js("$('#widget').innerHTML") #=> "ohaie"
96
+
97
+ ### Fetching Documents
98
+
99
+ Use `Harmony::Page.fetch(uri)` to create a page from a remote document.
100
+
101
+ require 'harmony'
102
+
103
+ page = Harmony::Page.fetch('http://example.com')
104
+ page.execute_js('document.title') #=> "Example Web Page"
105
+
106
+ `fetch` also accepts "file://" uris.
107
+
108
+ Install
109
+ -------
110
+
111
+ # There's a gem dependency bug in rubygems currently, so we'll have to
112
+ # install dependencies manually. This will be fixed soon.
113
+ gem install stackdeck
114
+ gem install johnson -v "2.0.0.pre1"
115
+
116
+ gem install harmony
117
+
118
+ See Also
119
+ --------
120
+
121
+ * [holygrail][20]: Harmony plugin for Rails tests
122
+
123
+ Acknowledgement
124
+ ---------------
125
+
126
+ Harmony is a thin DSL wrapper around three **amazing** libs, [Johnson][1],
127
+ [env.js][30] and [Envjs][2] . The authors of those libs have been doing a huge
128
+ amount of great work for quite a while, so please go recommend them on
129
+ WorkingWithRails right now and/or follow them on github:
130
+
131
+ [jbarnette][3], [tenderlove][4], [smparkes][5], [wycats][6], [matthewd][7], [thatcher][8], [jeresig][9]
132
+
133
+ Special thanks go to [smparkes][10] for his patient help, and for providing the
134
+ last puzzle pieces that made [everything][12] [work][11] [together][13].
135
+
136
+ Links
137
+ -----
138
+ * code: <http://github.com/mynyml/harmony>
139
+ * docs: <http://yardoc.org/docs/mynyml-harmony>
140
+ * wiki: <http://wiki.github.com/mynyml/harmony>
141
+ * bugs: <http://github.com/mynyml/harmony/issues>
142
+
143
+
144
+
145
+ YinYang ASCII art is © Normand Veilleux (nveilleuATemr1.emrDOTca)
146
+
147
+
148
+ [1]: http://github.com/jbarnette/johnson/
149
+ [2]: http://env-js.appspot.com/
150
+ [3]: http://www.workingwithrails.com/person/10668-john-barnette
151
+ [4]: http://github.com/tenderlove/
152
+ [5]: http://www.workingwithrails.com/person/11739-steven-parkes
153
+ [6]: http://www.workingwithrails.com/person/1805-yehuda-katz
154
+ [7]: http://www.workingwithrails.com/person/6221-matthew-draper
155
+ [8]: http://github.com/thatcher/
156
+ [9]: http://ejohn.org/
157
+ [10]: http://github.com/smparkes/
158
+ [11]: http://github.com/smparkes/env-js/commit/49abe259813a505b0761e6d31dde671344b5bc87#L0R279
159
+ [12]: http://groups.google.com/group/envjs/msg/4ac719f7db7912f5
160
+ [13]: http://gemcutter.org/gems/envjs
161
+ [20]: http://github.com/mynyml/holygrail
162
+ [30]: http://github.com/thatcher/env-js
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ def gem_opt
2
+ defined?(Gem) ? "-rubygems" : ""
3
+ end
4
+
5
+ # --------------------------------------------------
6
+ # Tests
7
+ # --------------------------------------------------
8
+ task(:default => "test:all")
9
+
10
+ namespace(:test) do
11
+
12
+ desc "Run all tests"
13
+ task(:all) do
14
+ exit system("ruby #{gem_opt} -I.:lib:test -e'%w( #{Dir['test/**/*_test.rb'].join(' ')} ).each {|p| require p }'")
15
+ end
16
+
17
+ desc "Run all tests on multiple ruby versions (requires rvm)"
18
+ task(:portability) do
19
+ versions = %w( 1.8.6 1.8.7 )
20
+ versions.each do |version|
21
+ system <<-BASH
22
+ bash -c 'source ~/.rvm/scripts/rvm;
23
+ rvm use #{version};
24
+ echo "--------- #{version} ----------";
25
+ rake -s test:all'
26
+ BASH
27
+ end
28
+ end
29
+ end
30
+
31
+ # --------------------------------------------------
32
+ # Docs
33
+ # --------------------------------------------------
34
+ desc "Generate YARD Documentation"
35
+ task :yardoc do
36
+ require 'yard'
37
+ YARD::CLI::Yardoc.run *%w( --no-private --no-highlight -o doc/yard --readme README.md --markup markdown - LICENSE )
38
+ end
39
+
data/docs.watchr ADDED
@@ -0,0 +1,25 @@
1
+ # Run me with:
2
+ # $ watchr docs.watchr
3
+
4
+ require 'yard'
5
+ # --------------------------------------------------
6
+ # Rules
7
+ # --------------------------------------------------
8
+ watch( 'lib/.*\.rb' ) { yard }
9
+ watch( 'README.md' ) { yard }
10
+
11
+ # --------------------------------------------------
12
+ # Signal Handling
13
+ # --------------------------------------------------
14
+ Signal.trap('QUIT') { yard } # Ctrl-\
15
+ Signal.trap('INT' ) { abort("\n") } # Ctrl-C
16
+
17
+ # --------------------------------------------------
18
+ # Helpers
19
+ # --------------------------------------------------
20
+ def yard
21
+ print "Updating yardocs... "; STDOUT.flush
22
+ YARD::CLI::Yardoc.run *%w( --no-private --no-highlight -o doc/yard --readme README.md --markup markdown - LICENSE )
23
+ print "done\n"
24
+ end
25
+
data/harmony.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ require 'lib/harmony'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "juliocesar-harmony"
5
+ s.summary = "Javascript + DOM in your ruby, the simple way"
6
+ s.description = "Javascript + DOM in your ruby, the simple way."
7
+ s.author = "Julio Cesar Ody"
8
+ s.email = "julioody@gmail.com"
9
+ s.homepage = "http://github.com/juliocesar/harmony"
10
+ s.require_path = "lib"
11
+ s.rubygems_version = "1.3.5"
12
+ s.version = Harmony::VERSION
13
+ s.files = File.read("Manifest").strip.split("\n")
14
+
15
+ s.add_dependency 'johnson', '2.0.0.pre2'
16
+ s.add_dependency 'envjs', '0.1.4'
17
+ s.add_development_dependency 'minitest'
18
+ end
data/lib/harmony.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Harmony
2
+ VERSION = '0.5.2'
3
+
4
+ autoload :Page, 'harmony/page'
5
+ end
@@ -0,0 +1,123 @@
1
+ require 'pathname'
2
+ require 'tempfile'
3
+
4
+ require 'johnson/tracemonkey'
5
+ require 'envjs/runtime'
6
+
7
+ module Harmony
8
+ class Page
9
+
10
+ # Window factory
11
+ #
12
+ # @private
13
+ module Window #:nodoc:
14
+ extend self
15
+
16
+ # Cache the initial runtime. Parsing env.js (done automatically when
17
+ # Envjs::Runtime is extended) takes a while, so we only want to do this
18
+ # once.
19
+ #
20
+ # @private
21
+ BASE_RUNTIME = Johnson::Runtime.new
22
+ BASE_RUNTIME.extend(Envjs::Runtime)
23
+
24
+ def from_uri(uri)
25
+ BASE_RUNTIME.evaluate("window.open('#{uri}')")
26
+ end
27
+
28
+ def from_document(document)
29
+ Tempfile.open('harmony') {|f| f << document; @path = f.path }
30
+ from_uri("file://#{@path}")
31
+ end
32
+
33
+ def blank
34
+ from_uri('about:blank')
35
+ end
36
+ end
37
+
38
+ # Create page from remote document.
39
+ #
40
+ # @example
41
+ #
42
+ # Page.fetch('http://montrealrb.org')
43
+ # Page.fetch('http://localhost:3000')
44
+ # Page.fetch('file:///home/mynyml/www/foo/index.html')
45
+ #
46
+ # @param [String] uri
47
+ # uri to fetch document from
48
+ #
49
+ # @return [Page]
50
+ # new page object preloaded with fetched document
51
+ #
52
+ def self.fetch(uri)
53
+ page = new
54
+ page.instance_variable_set(:@window, Window.from_uri(uri))
55
+ page
56
+ end
57
+
58
+ # Create new page containing given document.
59
+ #
60
+ # @param [String] document
61
+ # HTML document. Defaults to an "about:blank" window, with the basic
62
+ # structure: `<html><head><title></title></head><body></body></html>`
63
+ #
64
+ def initialize(document=nil)
65
+ @window = Window.from_document(document) if document
66
+ end
67
+
68
+ # Load one or more javascript files in page's context
69
+ #
70
+ # @param [#to_s, #to_s, ...] paths
71
+ # paths to js file
72
+ # @return [Page] self
73
+ #
74
+ def load(*paths)
75
+ paths.flatten.each do |path|
76
+ window.load(path.to_s)
77
+ end
78
+ self
79
+ end
80
+
81
+ # Evaluate Javascript code within this page's context.
82
+ #
83
+ # @param [String] code
84
+ # javascript code to execute
85
+ #
86
+ # @return [Object]
87
+ # last javascript statement's value, cast to a ruby object
88
+ #
89
+ def execute_js(code)
90
+ window.evaluate(code)
91
+ end
92
+ alias :x :execute_js
93
+
94
+ # DOM document's `window` object. Equivalent to the return value of
95
+ # `page.execute_js('window')`
96
+ #
97
+ # @return [Object]
98
+ # window DOM object
99
+ #
100
+ def window
101
+ @window ||= Window.blank
102
+ end
103
+
104
+ # Convenience method, equivalent to the return value of
105
+ # `page.execute_js('window.document')`
106
+ #
107
+ # @return [Object]
108
+ # document DOM object
109
+ #
110
+ def document
111
+ window.document
112
+ end
113
+
114
+ # Page as html document
115
+ #
116
+ # @return [String] html
117
+ #
118
+ def to_html
119
+ document.innerHTML
120
+ end
121
+ end
122
+ end
123
+
data/specs.watchr ADDED
@@ -0,0 +1,36 @@
1
+ # Run me with:
2
+ # $ watchr specs.watchr
3
+
4
+ # --------------------------------------------------
5
+ # Rules
6
+ # --------------------------------------------------
7
+ watch( '^test.*/.*_test\.rb' ) {|m| ruby m[0] }
8
+ watch( '^lib/(.*)\.rb' ) {|m| ruby "test/#{m[1]}_test.rb" }
9
+ watch( '^lib/harmony/(.*)\.rb' ) {|m| ruby "test/#{m[1]}_test.rb" }
10
+ watch( '^test/test_helper\.rb' ) { ruby tests }
11
+
12
+ # --------------------------------------------------
13
+ # Signal Handling
14
+ # --------------------------------------------------
15
+ Signal.trap('QUIT') { ruby tests } # Ctrl-\
16
+ Signal.trap('INT' ) { abort("\n") } # Ctrl-C
17
+
18
+ # --------------------------------------------------
19
+ # Helpers
20
+ # --------------------------------------------------
21
+ def ruby(*paths)
22
+ run "ruby #{gem_opt} -I.:lib:test -e'%w( #{paths.flatten.join(' ')} ).each {|p| require p }'"
23
+ end
24
+
25
+ def tests
26
+ Dir['test/**/*_test.rb']
27
+ end
28
+
29
+ def run( cmd )
30
+ puts cmd
31
+ system cmd
32
+ end
33
+
34
+ def gem_opt
35
+ defined?(Gem) ? "-rubygems" : ""
36
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/test_helper'
2
+
3
+ class HarmonyTest < MiniTest::Unit::TestCase
4
+ test "version" do
5
+ refute_nil Harmony::VERSION
6
+ end
7
+ end
8
+
data/test/page_test.rb ADDED
@@ -0,0 +1,101 @@
1
+ require 'test/test_helper'
2
+
3
+ class PageTest < MiniTest::Unit::TestCase
4
+ include Harmony
5
+
6
+ PAGE = Page.new
7
+
8
+ test "api" do
9
+ assert_respond_to Page, :fetch
10
+ assert_respond_to Page, :new
11
+ assert_respond_to PAGE, :window
12
+ assert_respond_to PAGE, :document
13
+ assert_respond_to PAGE, :execute_js
14
+ assert_respond_to PAGE, :x
15
+ assert_respond_to PAGE, :to_s
16
+ end
17
+
18
+ test "document shortcut" do
19
+ assert_equal PAGE.window.document, PAGE.document
20
+ end
21
+
22
+ test "executes javascript" do
23
+ assert_equal 7, PAGE.x('5+2')
24
+ end
25
+
26
+ test "excutes DOM-accessing javascript" do
27
+ page = Page.new(<<-HTML)
28
+ <html>
29
+ <head>
30
+ <title>Harmony</title>
31
+ </head>
32
+ <body>
33
+ <div></div>
34
+ <div></div>
35
+ </body>
36
+ </html>
37
+ HTML
38
+ assert_equal 'Harmony', page.document.title
39
+ assert_equal 2, page.x(<<-JS)
40
+ document.getElementsByTagName('div').length
41
+ JS
42
+ end
43
+
44
+ test "fetches remote document" do
45
+ path = tempfile(<<-HTML)
46
+ <html><head><title>foo</title></head><body></body></html>
47
+ HTML
48
+ page = Page.fetch("file://#{path}")
49
+ assert_equal 'foo', page.document.title
50
+ end
51
+
52
+ test "default window" do
53
+ assert_empty Page.new.document.title
54
+ end
55
+
56
+ test "cast to html" do
57
+ assert_equal "<html><head><title></title></head><body></body></html>", Page.new.to_html
58
+ end
59
+
60
+ test "loads javascript file" do
61
+ path = tempfile(<<-HTML)
62
+ function foo() { return 'bar' };
63
+ HTML
64
+ page = Page.new.load(path)
65
+ assert_equal 'bar', page.x('foo()')
66
+ end
67
+
68
+ test "can load multiple files as array" do
69
+ paths = []
70
+ paths << tempfile(<<-HTML)
71
+ function foo() { return 'bar' };
72
+ HTML
73
+ paths << tempfile(<<-HTML)
74
+ function moo() { return 'boo' };
75
+ HTML
76
+
77
+ page = Page.new.load(paths)
78
+ assert_equal 'bar', page.x('foo()')
79
+ assert_equal 'boo', page.x('moo()')
80
+ end
81
+
82
+ test "can load multiple files as splat" do
83
+ paths = []
84
+ paths << tempfile(<<-HTML)
85
+ function foo() { return 'bar' };
86
+ HTML
87
+ paths << tempfile(<<-HTML)
88
+ function moo() { return 'boo' };
89
+ HTML
90
+
91
+ page = Page.new.load(*paths)
92
+ assert_equal 'bar', page.x('foo()')
93
+ assert_equal 'boo', page.x('moo()')
94
+ end
95
+
96
+ private
97
+ def tempfile(content)
98
+ Tempfile.open('abc') {|f| f << content; @__path = f.path }
99
+ @__path
100
+ end
101
+ end
@@ -0,0 +1,13 @@
1
+ require 'minitest/autorun'
2
+
3
+ begin require 'ruby-debug'; rescue LoadError; end
4
+ begin require 'redgreen' ; rescue LoadError; end
5
+ begin require 'phocus' ; rescue LoadError; end
6
+
7
+ require 'lib/harmony'
8
+
9
+ class MiniTest::Unit::TestCase
10
+ def self.test(name, &block)
11
+ define_method("test_#{name}".gsub(/\s/,'_'), &block)
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: juliocesar-harmony
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.2
5
+ platform: ruby
6
+ authors:
7
+ - Julio Cesar Ody
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-24 00:00:00 +11:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: johnson
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.0.0.pre2
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: envjs
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.4
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: minitest
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ description: Javascript + DOM in your ruby, the simple way.
46
+ email: julioody@gmail.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files: []
52
+
53
+ files:
54
+ - .gitignore
55
+ - LICENSE
56
+ - Manifest
57
+ - README.md
58
+ - Rakefile
59
+ - docs.watchr
60
+ - harmony.gemspec
61
+ - lib/harmony.rb
62
+ - lib/harmony/page.rb
63
+ - specs.watchr
64
+ - test/harmony_test.rb
65
+ - test/page_test.rb
66
+ - test/test_helper.rb
67
+ has_rdoc: true
68
+ homepage: http://github.com/juliocesar/harmony
69
+ licenses: []
70
+
71
+ post_install_message:
72
+ rdoc_options: []
73
+
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: "0"
87
+ version:
88
+ requirements: []
89
+
90
+ rubyforge_project:
91
+ rubygems_version: 1.3.5
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Javascript + DOM in your ruby, the simple way
95
+ test_files: []
96
+