kuntoaji-harmony 0.5.7 → 0.5.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Harmony
1
+ Harmony - the memory reduced version ...
2
2
  =======
3
3
 
4
4
  .,ad88888888baa,
@@ -21,89 +21,19 @@ Harmony
21
21
  ""88888888888888888P"
22
22
  """"""""""""
23
23
 
24
- Summary
24
+ Why this new version of an already great gem?
25
25
  -------
26
26
 
27
- Harmony provides a simple DSL to execute javascript + DOM code within ruby.
27
+ We, at Cohuman, have been using Harmony in our Rspec text suite for javascript unit testing. For performance reasons, the original Harmony gem instantiated one Johnson js runtime per Harmony universe. Envjs was loaded into the runtime once and then each page was instantiated and loaded into this singleton runtime. This lead to a memory explosion since none of the pages created in our test suite are released until the entire suite finished running. Our 700 tests were taking over a gig of memory :(
28
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"
29
+ This is an experimental version of Harmony that instantiates a new Johnson runtime with Envjs for each page created. This means that we maintain the unit test isolation that Harmony pages provide while allowing each page to be garbage collected after the test is run. The penalty is, of course, performance. Creating a new Johnson runtime and loading it with the Envjs methods takes time.
96
30
 
97
- ### Fetching Documents
31
+ Ideally, Harmony should allow configuration for performance or memory optimization. Should there be demand we will make it happen!
98
32
 
99
- Use `Harmony::Page.fetch(uri)` to create a page from a remote document.
100
33
 
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.
34
+ Get the original, and learn more about the API
35
+ --------
36
+ http://github.com/mynyml/harmony
107
37
 
108
38
  Install
109
39
  -------
@@ -113,50 +43,8 @@ Install
113
43
  gem install stackdeck
114
44
  gem install johnson -v "2.0.0.pre3"
115
45
 
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
46
+ # download this version of the gem and install it manually:
47
+ git clone http://github.com/baccigalupi/harmony.git
48
+ cd harmony
49
+ sudo rake install
50
+
data/Rakefile CHANGED
@@ -8,10 +8,21 @@ end
8
8
  # --------------------------------------------------
9
9
  # Tests
10
10
  # --------------------------------------------------
11
- task(:default => "test:all")
12
11
 
13
- namespace(:test) do
12
+ # new rspec version
13
+ begin
14
+ require 'spec/rake/spectask'
15
+ Spec::Rake::SpecTask.new(:spec) do |spec|
16
+ spec.libs << 'lib' << 'spec'
17
+ spec.spec_files = FileList['spec/**/*_spec.rb']
18
+ end
19
+ task :default => :spec
20
+ rescue
21
+ task :default => "test:all"
22
+ end
14
23
 
24
+ # original minitest version
25
+ namespace(:test) do
15
26
  desc "Run all tests"
16
27
  task(:all) do
17
28
  exit system("ruby #{gem_opt} -I.:lib:test -e'%w( #{Dir['test/**/*_test.rb'].join(' ')} ).each {|p| require p }'")
data/harmony.gemspec CHANGED
@@ -6,11 +6,11 @@ Gem::Specification.new do |s|
6
6
  s.name = "kuntoaji-harmony"
7
7
  s.version = Harmony::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["mynyml", "Kunto Aji Kristianto"]
10
- s.email = ["mynyml@gmail.com", "kunto.aji.kr@gmail.com"]
9
+ s.authors = ["mynyml", "Kunto Aji Kristianto", "baccigalupi"]
10
+ s.email = ["mynyml@gmail.com", "kunto.aji.kr@gmail.com", "baccigalupi@gmail.com"]
11
11
  s.homepage = "http://github.com/kuntoaji/harmony"
12
12
  s.summary = %q{Javascript + DOM in your ruby, the simple way}
13
- s.description = %q{Javascript + DOM in your ruby, the simple way. Kuntoaji's version.}
13
+ s.description = %q{Javascript + DOM in your ruby, the simple way. More memory sensitive based on baccigalupi's repos. Kuntoaji's version.}
14
14
 
15
15
  #s.rubyforge_project = ""
16
16
 
data/lib/harmony/page.rb CHANGED
@@ -1,40 +1,20 @@
1
1
  require 'pathname'
2
2
  require 'tempfile'
3
+ require 'forwardable'
3
4
 
4
5
  require 'johnson/tracemonkey'
5
6
  require 'envjs/runtime'
6
7
 
7
8
  module Harmony
8
9
  class Page
9
-
10
- # Window factory
10
+ # DOM document's `window` object. Equivalent to the return value of
11
+ # `page.execute_js('window')`
11
12
  #
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
-
13
+ # @return [Object]
14
+ # window DOM object
15
+ #
16
+ attr_reader :window
17
+
38
18
  # Create page from remote document.
39
19
  #
40
20
  # @example
@@ -51,7 +31,7 @@ module Harmony
51
31
  #
52
32
  def self.fetch(uri)
53
33
  page = new
54
- page.instance_variable_set(:@window, Window.from_uri(uri))
34
+ page.window.open(uri)
55
35
  page
56
36
  end
57
37
 
@@ -62,7 +42,7 @@ module Harmony
62
42
  # structure: `<html><head><title></title></head><body></body></html>`
63
43
  #
64
44
  def initialize(document=nil)
65
- @window = Window.from_document(document) if document
45
+ @window = document ? Window.from_document(document) : Window.blank
66
46
  end
67
47
 
68
48
  # Load one or more javascript files in page's context
@@ -93,16 +73,6 @@ module Harmony
93
73
  end
94
74
  alias :x :execute_js
95
75
 
96
- # DOM document's `window` object. Equivalent to the return value of
97
- # `page.execute_js('window')`
98
- #
99
- # @return [Object]
100
- # window DOM object
101
- #
102
- def window
103
- @window ||= Window.blank
104
- end
105
-
106
76
  # Convenience method, equivalent to the return value of
107
77
  # `page.execute_js('window.document')`
108
78
  #
@@ -120,6 +90,47 @@ module Harmony
120
90
  def to_html
121
91
  document.innerHTML
122
92
  end
93
+
94
+ # Window factory
95
+ #
96
+ # @private
97
+ class Window
98
+ extend Forwardable
99
+
100
+ attr_reader :run_time
101
+ def_delegators :@run_time, :evaluate, :load
102
+ def_delegators :@browser, :document
103
+
104
+ def initialize(uri='about:blank')
105
+ open(uri)
106
+ end
107
+
108
+ def run_time
109
+ unless @run_time
110
+ @run_time = Johnson::Runtime.new
111
+ @run_time.extend Envjs::Runtime
112
+ end
113
+ @run_time
114
+ end
115
+
116
+ def open(uri)
117
+ @browser = run_time.evaluate("window.open('#{uri}')")
118
+ run_time
119
+ end
120
+
121
+ def self.from_uri(uri)
122
+ new(uri)
123
+ end
124
+
125
+ def self.from_document(document)
126
+ Tempfile.open('harmony') {|f| f << document; @path = f.path }
127
+ new("file://#{@path}")
128
+ end
129
+
130
+ def self.blank
131
+ new
132
+ end
133
+ end
123
134
  end
124
135
  end
125
136
 
@@ -1,3 +1,3 @@
1
1
  module Harmony
2
- VERSION = "0.5.7"
2
+ VERSION = "0.5.8"
3
3
  end
data/spec/page_spec.rb ADDED
@@ -0,0 +1,142 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ Page = Harmony::Page unless defined?( Page )
4
+
5
+ describe Harmony::Page do
6
+ before do
7
+ @blank = Page.new
8
+ end
9
+
10
+ describe 'api' do
11
+ CLASS_METHODS = [:fetch, :new]
12
+ INSTANCE_METHODS = [:window, :document, :execute_js, :x]
13
+
14
+ CLASS_METHODS.each do |page_method|
15
+ it "Page should respond to #{page_method}" do
16
+ Page.should respond_to(page_method)
17
+ end
18
+ end
19
+
20
+ INSTANCE_METHODS.each do |page_method|
21
+ it "Page instance should respond to #{page_method}" do
22
+ @blank.should respond_to(page_method)
23
+ end
24
+ end
25
+
26
+ it 'Page.document should be a shortcut for Page.window.document' do
27
+ window = mock('Window')
28
+ @blank.should_receive(:window).and_return(window)
29
+ window.should_receive(:document)
30
+ @blank.document
31
+ end
32
+ end
33
+
34
+ describe 'execution' do
35
+ it 'performs basic js' do
36
+ @blank.x('5+2').should == 7
37
+ end
38
+
39
+ it 'executes DOM-accessing js' do
40
+ page = Page.new(<<-HTML)
41
+ <html>
42
+ <head>
43
+ <title>Harmony</title>
44
+ </head>
45
+ <body>
46
+ <div></div>
47
+ <div></div>
48
+ </body>
49
+ </html>
50
+ HTML
51
+ page.document.title.should == 'Harmony'
52
+
53
+ (page.x(<<-JS)
54
+ document.getElementsByTagName('div').length
55
+ JS
56
+ ).should == 2
57
+ end
58
+ end
59
+
60
+ describe 'basic characteristics' do
61
+ it "Page fetches documents from remote locations" do
62
+ path = tempfile(<<-HTML)
63
+ <html><head><title>foo</title></head><body></body></html>
64
+ HTML
65
+ page = Page.fetch("file://#{path}")
66
+ page.document.title.should == 'foo'
67
+ end
68
+
69
+ describe 'default empty page' do
70
+ it "has no title" do
71
+ @blank.document.title.should be_empty
72
+ end
73
+
74
+ it '#to_html should produce an empty document' do
75
+ @blank.to_html.should == "<html><head><title></title></head><body></body></html>"
76
+ end
77
+ end
78
+ end
79
+
80
+ describe 'loading js files' do
81
+ it "works with one one path" do
82
+ path = tempfile(<<-JS)
83
+ function foo() { return 'bar' };
84
+ JS
85
+
86
+ page = Page.new.load(path)
87
+ page.x('foo()').should == 'bar'
88
+ end
89
+
90
+ it "takes an array of paths" do
91
+ paths = []
92
+ paths << tempfile(<<-JS)
93
+ function foo() { return 'bar' };
94
+ JS
95
+
96
+ paths << tempfile(<<-JS)
97
+ function moo() { return 'boo' };
98
+ JS
99
+
100
+ page = Page.new.load(paths)
101
+ page.x('foo()').should == 'bar'
102
+ page.x('moo()').should == 'boo'
103
+ end
104
+
105
+ it "can load multiple files with splat" do
106
+ paths = []
107
+ paths << tempfile(<<-JS)
108
+ function foo() { return 'bar' };
109
+ JS
110
+
111
+ paths << tempfile(<<-JS)
112
+ function moo() { return 'boo' };
113
+ JS
114
+
115
+ page = Page.new.load(*paths)
116
+ page.x('foo()').should == 'bar'
117
+ page.x('moo()').should == 'boo'
118
+ end
119
+ end
120
+
121
+ describe 'document context' do
122
+ it 'should use a different window for each page' do
123
+ @blank.window.should_not === Page.new.window
124
+ end
125
+
126
+ it 'should use a different runtime for each page' do
127
+ @blank.window.run_time.should_not === Page.new.window.run_time
128
+ end
129
+
130
+ it 'should keep a window/browser run time within the same page' do
131
+ @blank.window.run_time.should == @blank.window.run_time
132
+ end
133
+ end
134
+
135
+ def tempfile(content)
136
+ Tempfile.open('abc') do |f|
137
+ f << content
138
+ @__path = f.path
139
+ end
140
+ @__path
141
+ end
142
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require 'harmony'
5
+ require 'spec'
6
+
7
+ Spec::Runner.configure do |config|
8
+ end
metadata CHANGED
@@ -1,22 +1,23 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kuntoaji-harmony
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 7
10
- version: 0.5.7
9
+ - 8
10
+ version: 0.5.8
11
11
  platform: ruby
12
12
  authors:
13
13
  - mynyml
14
14
  - Kunto Aji Kristianto
15
+ - baccigalupi
15
16
  autorequire:
16
17
  bindir: bin
17
18
  cert_chain: []
18
19
 
19
- date: 2011-02-03 00:00:00 +07:00
20
+ date: 2011-02-20 00:00:00 +07:00
20
21
  default_executable:
21
22
  dependencies:
22
23
  - !ruby/object:Gem::Dependency
@@ -67,10 +68,11 @@ dependencies:
67
68
  version: "0"
68
69
  type: :development
69
70
  version_requirements: *id003
70
- description: Javascript + DOM in your ruby, the simple way. Kuntoaji's version.
71
+ description: Javascript + DOM in your ruby, the simple way. More memory sensitive based on baccigalupi's repos. Kuntoaji's version.
71
72
  email:
72
73
  - mynyml@gmail.com
73
74
  - kunto.aji.kr@gmail.com
75
+ - baccigalupi@gmail.com
74
76
  executables: []
75
77
 
76
78
  extensions: []
@@ -89,6 +91,8 @@ files:
89
91
  - lib/harmony.rb
90
92
  - lib/harmony/page.rb
91
93
  - lib/harmony/version.rb
94
+ - spec/page_spec.rb
95
+ - spec/spec_helper.rb
92
96
  - specs.watchr
93
97
  - test/harmony_test.rb
94
98
  - test/page_test.rb
@@ -128,6 +132,8 @@ signing_key:
128
132
  specification_version: 3
129
133
  summary: Javascript + DOM in your ruby, the simple way
130
134
  test_files:
135
+ - spec/page_spec.rb
136
+ - spec/spec_helper.rb
131
137
  - test/harmony_test.rb
132
138
  - test/page_test.rb
133
139
  - test/test_helper.rb