bowser 0.5.4 → 1.0.0

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.
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