bowser 0.5.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e29282cc18c5cb7189e25666a7145156a07b66721fa379a2d642208c044644d5
4
- data.tar.gz: 370e47229f7089509074177c00037a2d8a26df1fa23c143f821af1405da379cf
3
+ metadata.gz: 68cdf98fa8eacbad1336d1a69623d7cc5eeec542f8444e8b3ddc5dde76881abc
4
+ data.tar.gz: 9bf407b1709c4495a9b67dee92bba52877ea403b875dbaea3c485c7d70607304
5
5
  SHA512:
6
- metadata.gz: 2980467c77a84e280349aa3a6d8c628aa07f66149b9682a0ca7942ea14bce1b93b4c683a2583e9d14dd6d04e7dbb3cbc03b737ad2e635348d039c4aeffa444fc
7
- data.tar.gz: 4a01ca82ce5d29435d1b4d91acb40d54078db58a20a53a82d31a7330e7ca5acc24f0640ec9020fd932369bffd53bf060d1ad2a4e4ff71a3679ce3297fc9e7474
6
+ metadata.gz: e001a975cd34a1dedab2dae89e6f83f0c3e0d92d9d1b7f316d9953d7ced53efae81b8b23e6f40ccb542f26a8358db5f3792bd91b689d03ae523401023124d10a
7
+ data.tar.gz: e57b4be10b4009cd1548190c02642182763978e87832688e4daaa3be60883a7742007fec341ecd76950d48ec634727b14e922175dd2bc239e90701ac05cd5a72
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --format documentation
2
2
  --color
3
+ --require spec_helper
data/Gemfile CHANGED
@@ -2,3 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in bowser.gemspec
4
4
  gemspec
5
+
6
+ gem 'pry'
7
+ gem 'opal', '~> 0.10.0'
data/README.md CHANGED
@@ -29,24 +29,34 @@ Bowser.document # Handle to the current document
29
29
  Bowser.window # Handle to the current window
30
30
  ```
31
31
 
32
- ### AJAX support
32
+ ### HTTP support
33
33
 
34
- To make HTTP requests to your API, for example, you can do:
34
+ To load HTTP support, require it by running:
35
+
36
+ ```ruby
37
+ require 'bowser/http'
38
+ ```
39
+
40
+ To make HTTP requests to your API, you can use `Bowser::HTTP.fetch`:
35
41
 
36
42
  ```ruby
37
43
  Bowser::HTTP.fetch('/api/things')
38
44
  ```
39
45
 
40
- It returns a `Promise`, which you can call `then`, `fail`, or `always` on in order to execute a block of code based on success, failure, or either one, respectively.
46
+ It returns a [`Bowser::Promise`](https://github.com/clearwater-rb/bowser/blob/master/opal/bowser/promise.rb), on which you can call `then` or `catch` in order to execute a block of code based on success or failure, respectively.
41
47
 
42
48
  ```ruby
43
49
  Bowser::HTTP.fetch(url)
50
+ .then(&:json) # JSONify the response
44
51
  .then { |response| do_something_with(response.json) }
45
- .fail { |exception| warn exception.message }
46
- .always { log "Fetched #{url}" }
52
+ .catch { |exception| warn exception.message }
47
53
  ```
48
54
 
49
- The current implementation uses the `Promise` class from the Opal standard library, but it is not fully A+-compliant, so we're in the process of implementing our own.
55
+ To make `POST` requests, you can pass the `method` keyword argument. The body of the post is represented in the `data` keyword argument. This is in contrast to the ES6 `fetch` function, which uses `body`, but requires a string. The `data` argument lets you pass in a string or a hash, which will be converted to JSON:
56
+
57
+ ```ruby
58
+ Bowser::HTTP.fetch(url, method: :post, data: { name: 'Bowser' })
59
+ ```
50
60
 
51
61
  ## Contributing
52
62
 
data/bin/console CHANGED
@@ -10,5 +10,5 @@ require "bowser"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
14
- IRB.start
13
+ require "pry"
14
+ pry
data/bowser.gemspec CHANGED
@@ -23,4 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 1.10"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
25
  spec.add_development_dependency "opal-rspec"
26
+ spec.add_development_dependency "rspec"
26
27
  end
@@ -1,3 +1,3 @@
1
1
  module Bowser
2
- VERSION = "0.5.4"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -1,9 +1,10 @@
1
1
  require 'bowser/event_target'
2
- require 'bowser/file_list'
3
2
  require 'bowser/delegate_native'
4
- require 'bowser/iterable'
5
3
 
6
4
  module Bowser
5
+ autoload :FileList, 'bowser/file_list'
6
+ autoload :Iterable, 'bowser/iterable'
7
+
7
8
  # Wrap a native DOM element
8
9
  class Element
9
10
  include EventTarget
@@ -1,5 +1,5 @@
1
1
  require 'bowser/event_target'
2
- require 'promise'
2
+ require 'bowser/promise'
3
3
 
4
4
  module Bowser
5
5
  class FileList
@@ -1,4 +1,4 @@
1
- require 'promise'
1
+ require 'bowser/promise'
2
2
 
3
3
  module Bowser
4
4
  class Geolocation
data/opal/bowser/http.rb CHANGED
@@ -1,6 +1,4 @@
1
- require 'native'
2
- require 'promise'
3
-
1
+ require 'bowser/promise'
4
2
  require 'bowser/http/request'
5
3
  require 'bowser/http/form_data'
6
4
 
@@ -1,5 +1,5 @@
1
1
  require 'bowser/event_target'
2
- require 'promise'
2
+ require 'bowser/promise'
3
3
 
4
4
  module Bowser
5
5
  class IndexedDB
@@ -20,18 +20,17 @@ module Bowser
20
20
  end
21
21
  request.on :success do |event|
22
22
  @native = event.target.result
23
+ @open = true
23
24
 
24
25
  @thens.each(&:call)
25
- @thens.clear
26
+ @thens = []
26
27
  end
27
28
 
28
29
  request.on :upgradeneeded do |event|
29
- puts 'upgradeneeded'
30
30
  @native = event.target.result
31
31
 
32
32
  if block_given?
33
33
  yield self
34
- puts 'upgraded'
35
34
  else
36
35
  raise ArgumentError, "You must provide a block to `#{self.class}.new` in order to set up the database if the user's browser does not have it."
37
36
  end
@@ -49,15 +48,33 @@ module Bowser
49
48
  # is the end state we want after this method call anyway.
50
49
  end
51
50
 
51
+ def [] store
52
+ transaction(store).object_store(store)
53
+ end
54
+
55
+ def put **things # TODO: Come up with a less terrible name
56
+ things.each do |store_name, records|
57
+ transaction(store_name, :readwrite)
58
+ .object_store(store_name)
59
+ .tap do |store|
60
+ records.each do |record|
61
+ store.put record
62
+ end
63
+ end
64
+ end
65
+ end
66
+
52
67
  def transaction name, mode=:readonly
53
68
  Transaction.new(`#@native.transaction(#{name}, #{mode})`)
54
69
  end
55
70
 
56
71
  def then &block
57
- if @native
58
- block.call
72
+ if @open
73
+ Promise.resolve block.call
59
74
  else
60
- @thens << block
75
+ Promise.new do |p|
76
+ @thens << proc { p.resolve block.call }
77
+ end
61
78
  end
62
79
  end
63
80
 
@@ -111,22 +128,25 @@ module Bowser
111
128
  p
112
129
  end
113
130
 
114
- def get_all klass, count: `undefined`
115
- p = Promise.new
116
- query = block_given? ? yield(Query.new) : `undefined`
117
-
118
- request = Request.new(`#@native.getAll(#{query}, #{count})`)
119
- request.on :success do |event|
120
- p.resolve event.target.result.map { |js_obj|
121
- `delete #{js_obj}.$$id` # Remove old Ruby runtime metadata
122
- `Object.assign(#{klass.allocate}, #{js_obj})`
123
- }
124
- end
125
- request.on :error do |event|
126
- p.reject event.target.result
131
+ def get_all klass, count: nil, index: nil
132
+ Promise.new do |p|
133
+ query = block_given? ? yield(Query.new) : `undefined`
134
+
135
+ request = if index
136
+ index(index).get_all(klass, count: count)
137
+ else
138
+ Request.new(`#@native.getAll(#{query}, #{count || `undefined`})`)
139
+ end
140
+ request.on :success do |event|
141
+ p.resolve event.target.result.map { |js_obj|
142
+ `delete #{js_obj}.$$id` # Remove old Ruby runtime metadata
143
+ `Object.assign(#{klass.allocate}, #{js_obj})`
144
+ }
145
+ end
146
+ request.on :error do |event|
147
+ p.reject event.target.result
148
+ end
127
149
  end
128
-
129
- p
130
150
  end
131
151
 
132
152
  def index name
@@ -0,0 +1,166 @@
1
+ module Bowser
2
+ class Promise
3
+ attr_reader :value
4
+
5
+ def self.race promises
6
+ new do |promise|
7
+ promises.each do |p|
8
+ p.then { |value| promise.resolve value }
9
+ p.catch { |reason| promise.reject reason }
10
+ end
11
+ end
12
+ end
13
+
14
+ def self.all promises
15
+ new do |promise|
16
+ promises.each do |p|
17
+ p.then do |value|
18
+ promise.resolve promises.map(&:value) if promises.all?(&:resolved?)
19
+ end
20
+
21
+ p.catch { |reason| promise.reject reason }
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.resolve value=nil
27
+ new { |p| p.resolve value }
28
+ end
29
+
30
+ def self.reject value
31
+ new { |p| p.reject value }
32
+ end
33
+
34
+ def initialize
35
+ @callbacks = []
36
+
37
+ yield self if block_given?
38
+ end
39
+
40
+ def then &block
41
+ self.class.new do |p|
42
+ callback = SuccessCallback.new(p, block)
43
+
44
+ if pending?
45
+ @callbacks << callback
46
+ elsif resolved?
47
+ callback.resolve value
48
+ elsif rejected?
49
+ callback.reject value
50
+ end
51
+ end
52
+ end
53
+
54
+ def catch &block
55
+ self.class.new do |p|
56
+ callback = FailureCallback.new(p, block)
57
+
58
+ if pending?
59
+ @callbacks << callback
60
+ elsif resolved?
61
+ callback.resolve value
62
+ elsif rejected?
63
+ callback.reject value
64
+ end
65
+ end
66
+ end
67
+
68
+ def resolve value=nil
69
+ return if settled?
70
+
71
+ case value
72
+ when NativeValue
73
+ resolve_value value
74
+ when self
75
+ reject TypeError.new('Cannot resolve a promise with itself')
76
+ when Promise
77
+ value
78
+ .then { |v| resolve v }
79
+ .catch { |v| reject v }
80
+ else
81
+ resolve_value value
82
+ end
83
+ end
84
+
85
+ def resolve_value value
86
+ @value = value
87
+ @state = :resolved
88
+ @callbacks.each { |callback| callback.resolve value }
89
+ @callbacks.clear
90
+ end
91
+
92
+ def reject reason
93
+ return if settled?
94
+
95
+ case value
96
+ when Promise
97
+ value.catch { |v| reject v }
98
+ else
99
+ @value = reason
100
+ @state = :rejected
101
+ @callbacks.each do |callback|
102
+ callback.reject reason
103
+ end
104
+ @callbacks.clear
105
+ end
106
+ end
107
+
108
+ def resolved?
109
+ @state == :resolved
110
+ end
111
+
112
+ def rejected?
113
+ @state == :rejected
114
+ end
115
+
116
+ def pending?
117
+ !settled?
118
+ end
119
+
120
+ def settled?
121
+ rejected? || resolved?
122
+ end
123
+
124
+ class Callback
125
+ def initialize promise, block
126
+ @promise = promise
127
+ @block = block || proc { |value| value }
128
+ end
129
+ end
130
+
131
+ class SuccessCallback < Callback
132
+ def resolve value
133
+ @promise.resolve @block.call(value)
134
+ rescue => e
135
+ reject e
136
+ end
137
+
138
+ def reject value
139
+ @promise.reject value
140
+ end
141
+ end
142
+
143
+ class FailureCallback < Callback
144
+ def resolve value
145
+ @promise.resolve value
146
+ end
147
+
148
+ def reject value
149
+ @promise.resolve @block.call(value)
150
+ rescue => e
151
+ @promise.reject e
152
+ end
153
+ end
154
+
155
+ NativeValue = Object.new.tap do |native|
156
+ # Determines whether something is a native JS value. Returns false if
157
+ # we're not running on a JS VM. Otherwise, it returns whether the value
158
+ # is a JS primitive (string, number, undefined, null) or a native JS
159
+ # object.
160
+ def native.=== value
161
+ RUBY_ENGINE == 'opal' &&
162
+ `value == null || value.$$is_string || value.$$is_number || !('$$class' in value)`
163
+ end
164
+ end
165
+ end
166
+ end
@@ -1,4 +1,4 @@
1
- require 'promise'
1
+ require 'bowser/promise'
2
2
 
3
3
  module Bowser
4
4
  class ServiceWorker
@@ -1,5 +1,6 @@
1
1
  require 'bowser/delegate_native'
2
2
  require 'bowser/event_target'
3
+ require 'bowser/promise'
3
4
 
4
5
  module Bowser
5
6
  module Window
@@ -20,17 +21,24 @@ module Bowser
20
21
  end
21
22
  else
22
23
  def animation_frame &block
23
- delay(1.0 / 60, &block)
24
+ delay(0, &block)
24
25
  self
25
26
  end
26
27
  end
27
28
 
28
- # Run the given block after the specified number of seconds has passed.
29
- #
30
- # @param duration [Numeric] the number of seconds to wait
31
29
  def delay duration, &block
32
- `setTimeout(function() { #{block.call} }, duration * 1000)`
33
- self
30
+ Promise.new do |p|
31
+ function = proc do
32
+ begin
33
+ yield if block_given?
34
+ p.resolve
35
+ rescue => e
36
+ p.reject e
37
+ end
38
+ end
39
+
40
+ set_timeout duration, &block
41
+ end
34
42
  end
35
43
 
36
44
  # Run the given block every `duration` seconds
@@ -38,7 +46,11 @@ module Bowser
38
46
  # @param duration [Numeric] the number of seconds between runs
39
47
  def interval duration, &block
40
48
  `setInterval(function() { #{block.call} }, duration * 1000)`
41
- self
49
+ end
50
+ alias set_interval interval
51
+
52
+ def set_timeout duration, &block
53
+ `setTimeout(function() { #{block.call} }, duration * 1000)`
42
54
  end
43
55
 
44
56
  # @return [Location] the browser's Location object
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bowser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Gaskins
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-06 00:00:00.000000000 Z
11
+ date: 2018-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opal
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
75
89
  description:
76
90
  email:
77
91
  - jgaskins@gmail.com
@@ -109,6 +123,7 @@ files:
109
123
  - opal/bowser/http/response.rb
110
124
  - opal/bowser/indexed_db.rb
111
125
  - opal/bowser/iterable.rb
126
+ - opal/bowser/promise.rb
112
127
  - opal/bowser/service_worker.rb
113
128
  - opal/bowser/service_worker/cache_storage.rb
114
129
  - opal/bowser/service_worker/clients.rb
@@ -141,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
156
  version: '0'
142
157
  requirements: []
143
158
  rubyforge_project:
144
- rubygems_version: 2.7.3
159
+ rubygems_version: 2.7.6
145
160
  signing_key:
146
161
  specification_version: 4
147
162
  summary: Minimalist browser support for Opal apps