clearwater 1.0.0.beta5 → 1.0.0.rc1

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
  SHA1:
3
- metadata.gz: 0c83b9a2ad7fe21e4f47f356a63f64e787f8f7ac
4
- data.tar.gz: f35bd0d6f10bc01809b33b9eadaf53f7276edbce
3
+ metadata.gz: 7a977102139bfa209ce1a27d10bb2a54c62f8fde
4
+ data.tar.gz: 16d3f137ac9d4d7c613f9b3d5e82ea761d72bc62
5
5
  SHA512:
6
- metadata.gz: 4c72ec18e0557aa59bebba66aaca56ad70d4543f7065193e4519be52532453f29937037d01b6495308dad4746988c63b9db94bc1b056b2ee5fa4532b9fce34bd
7
- data.tar.gz: d58b23dbe9b28e15197902a4e25e3f4e33e678ea0681756fe440b192a660f4f8f67b30b56b6b052b78831c15e6e4620a3a40839c243fd7a9d839b7505daff284
6
+ metadata.gz: 5bb2ad0849af13dd873b464a59d7c38c0d9f259b86277d6b0067b3ece77d94ff8ffd84b496f2833d778e643f6b8cf27aa70c0a5a60d53e53a3040a01414dc055
7
+ data.tar.gz: 8aaee323980734782f5751707c5082e4071ea777fede96a562ef63acf4c6b6b6aee6f1a062c610d48de84fb529ccc172031adaf578b2ba90e0b6af605eff690e
@@ -0,0 +1,17 @@
1
+ module Clearwater
2
+ class Application
3
+ attr_reader :component, :router
4
+
5
+ def initialize options={}
6
+ @router = options.fetch(:router) { Router.new }
7
+ @component = options.fetch(:component) { nil }
8
+ router.application = self
9
+ component.router = router
10
+ end
11
+
12
+ def render
13
+ router.set_outlets
14
+ component.to_s
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module Clearwater
2
+ module BlackBoxNode
3
+ def to_s
4
+ node.to_s
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ module Clearwater
2
+ module CachedRender
3
+ end
4
+ end
@@ -0,0 +1,104 @@
1
+ require 'clearwater/component/html_tags'
2
+ require 'clearwater/dom_reference'
3
+
4
+ module Clearwater
5
+ module Component
6
+ extend self
7
+
8
+ attr_accessor :outlet
9
+ attr_accessor :router
10
+
11
+ def render
12
+ end
13
+
14
+ HTML_TAGS.each do |tag_name|
15
+ define_method tag_name do |attributes=nil, content=nil|
16
+ tag(tag_name, attributes, content)
17
+ end
18
+ end
19
+
20
+ def tag tag_name, attributes=nil, content=nil
21
+ unless attributes.nil? || attributes.is_a?(Hash)
22
+ content = attributes
23
+ attributes = nil
24
+ end
25
+
26
+ Tag.new(tag_name, attributes, content)
27
+ end
28
+
29
+ def to_s
30
+ html = render.to_s
31
+ if html.respond_to? :html_safe
32
+ html = html.html_safe
33
+ end
34
+
35
+ html
36
+ end
37
+
38
+ def params
39
+ router.params_for_path(router.current_path)
40
+ end
41
+
42
+ def call &block
43
+ end
44
+
45
+ class Tag
46
+ def initialize tag_name, attributes=nil, content=nil
47
+ @tag_name = tag_name
48
+ @attributes = sanitize_attributes(attributes)
49
+ @content = content
50
+ end
51
+
52
+ def to_html
53
+ html = "<#{@tag_name}"
54
+ if @attributes
55
+ @attributes.each do |attr, value|
56
+ html << " #{attr}=#{value.to_s.inspect}"
57
+ end
58
+ end
59
+ if @content
60
+ html << '>'
61
+ html << sanitize_content(@content)
62
+ html << "</#{@tag_name}>"
63
+ else
64
+ html << '/>'
65
+ end
66
+
67
+ html
68
+ end
69
+ alias to_s to_html
70
+
71
+ def sanitize_attributes attributes
72
+ return attributes unless attributes.is_a? Hash
73
+
74
+ if attributes.key? :class_name or attributes.key? :className
75
+ attributes[:class] ||= attributes.delete(:class_name) || attributes.delete(:className)
76
+ end
77
+
78
+ if Hash === attributes[:style]
79
+ attributes[:style] = attributes[:style].map { |attr, value|
80
+ attr = attr.to_s.tr('_', '-')
81
+ "#{attr}:#{value}"
82
+ }.join(';')
83
+ end
84
+
85
+ attributes.reject! do |key, handler|
86
+ key[0, 2] == 'on' || DOMReference === handler
87
+ end
88
+
89
+ attributes
90
+ end
91
+
92
+ def sanitize_content content
93
+ case content
94
+ when Array
95
+ content.map { |c| sanitize_content c }.join
96
+ when String
97
+ content.gsub('<', '&lt;')
98
+ else
99
+ content.to_s
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,7 @@
1
+ module Clearwater
2
+ class DOMReference
3
+ def to_s
4
+ ''.freeze
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ require 'clearwater/component'
2
+
3
+ class Link
4
+ include Clearwater::Component
5
+
6
+ def initialize attributes, content
7
+ @attributes = attributes
8
+ @content = content
9
+ end
10
+
11
+ def render
12
+ a(@attributes, @content)
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module Clearwater
2
- VERSION = "1.0.0.beta5"
2
+ VERSION = "1.0.0.rc1"
3
3
  end
data/lib/clearwater.rb CHANGED
@@ -1,8 +1,15 @@
1
1
  require "opal"
2
2
  require "bowser"
3
+ require "clearwater/component"
4
+ require 'clearwater/link'
5
+ $:.unshift File.expand_path(File.join('..', '..', 'shared'), __FILE__)
6
+ require 'clearwater/router'
7
+ require 'clearwater/application'
3
8
 
4
9
  module Clearwater
5
10
  require_relative "clearwater/version"
6
11
  end
7
12
 
8
- Opal.append_path(File.expand_path(File.join("..", "..", "opal"), __FILE__).untaint)
13
+ %w(opal shared).each do |dir|
14
+ Opal.append_path(File.expand_path(File.join("..", "..", dir), __FILE__).untaint)
15
+ end
@@ -24,6 +24,12 @@ module Clearwater
24
24
  router.application = self
25
25
  component.router = router if component
26
26
 
27
+ if `#@component.type === 'Thunk' && typeof #@component.render === 'function'`
28
+ warn "Application root component (#{@component}) points to a cached " +
29
+ "component. Cached components must not be persistent components, " +
30
+ "such as application roots or routing targets."
31
+ end
32
+
27
33
  @document.on 'visibilitychange' do
28
34
  if @render_on_visibility_change
29
35
  @render_on_visibility_change = false
@@ -1,123 +1,10 @@
1
1
  require 'clearwater/virtual_dom'
2
+ require 'clearwater/component/html_tags'
2
3
 
3
4
  module Clearwater
4
5
  module Component
5
6
  attr_accessor :router, :outlet
6
7
 
7
- HTML_TAGS = %w(
8
- a
9
- abbr
10
- address
11
- area
12
- article
13
- aside
14
- audio
15
- b
16
- base
17
- bdi
18
- bdo
19
- blockquote
20
- body
21
- br
22
- button
23
- canvas
24
- caption
25
- cite
26
- code
27
- col
28
- colgroup
29
- command
30
- data
31
- datalist
32
- dd
33
- del
34
- details
35
- dfn
36
- dialog
37
- div
38
- dl
39
- dt
40
- em
41
- embed
42
- fieldset
43
- figcaption
44
- figure
45
- footer
46
- form
47
- h1
48
- h2
49
- h3
50
- h4
51
- h5
52
- h6
53
- head
54
- header
55
- hgroup
56
- hr
57
- html
58
- i
59
- iframe
60
- img
61
- input
62
- ins
63
- kbd
64
- keygen
65
- label
66
- legend
67
- li
68
- link
69
- main
70
- map
71
- mark
72
- menu
73
- meta
74
- meter
75
- nav
76
- noscript
77
- object
78
- ol
79
- optgroup
80
- option
81
- output
82
- p
83
- param
84
- pre
85
- progress
86
- q
87
- rp
88
- rt
89
- ruby
90
- s
91
- samp
92
- script
93
- section
94
- select
95
- small
96
- source
97
- span
98
- strong
99
- style
100
- sub
101
- summary
102
- sup
103
- table
104
- tbody
105
- td
106
- textarea
107
- tfoot
108
- th
109
- thead
110
- time
111
- title
112
- tr
113
- track
114
- u
115
- ul
116
- var
117
- video
118
- wbr
119
- )
120
-
121
8
  def params
122
9
  router.params
123
10
  end
@@ -125,23 +12,23 @@ module Clearwater
125
12
  def self.sanitize_attributes attributes
126
13
  return attributes unless attributes.is_a? Hash
127
14
 
15
+ attributes.each do |key, value|
16
+ if `key.slice(0, 2)` == 'on'
17
+ attributes[key] = proc do |event|
18
+ value.call(Bowser::Event.new(event))
19
+ end
20
+ end
21
+ end
22
+
128
23
  # Allow specifying `class` instead of `class_name`.
129
24
  # Note: `class_name` is still allowed
130
- if attributes.key? :class
131
- if attributes.key? :class_name
25
+ if attributes.key?(:class)
26
+ if attributes.key?(:class_name)
132
27
  warn "You have both `class` and `class_name` attributes for this " +
133
28
  "element. `class` takes precedence: #{attributes}"
134
29
  end
135
30
 
136
- attributes[:class_name] = attributes.delete(:class)
137
- end
138
-
139
- attributes.each do |key, handler|
140
- if key[0, 2] == 'on'
141
- attributes[key] = proc do |event|
142
- handler.call(Bowser::Event.new(event))
143
- end
144
- end
31
+ attributes[:class_name] = attributes.delete :class
145
32
  end
146
33
 
147
34
  attributes
@@ -150,8 +37,8 @@ module Clearwater
150
37
  def self.sanitize_content content
151
38
  %x{
152
39
  if(content && content.$$class) {
153
- if(content.$$class === Opal.Array) {
154
- return #{content.map { |c| `self.$sanitize_content(c)` }};
40
+ if(content.$$is_array) {
41
+ return #{content.map { |c| sanitize_content(c) }};
155
42
  } else {
156
43
  var render = content.$render;
157
44
 
@@ -177,16 +64,18 @@ module Clearwater
177
64
 
178
65
  HTML_TAGS.each do |tag_name|
179
66
  define_method(tag_name) do |attributes, content|
67
+ %x{
68
+ if(!(attributes === nil || attributes.$$is_hash)) {
69
+ content = attributes;
70
+ attributes = nil;
71
+ }
72
+ }
73
+
180
74
  tag(tag_name, attributes, content)
181
75
  end
182
76
  end
183
77
 
184
78
  def tag tag_name, attributes=nil, content=nil
185
- if !(`attributes.$$is_hash || attributes === #{nil}`)
186
- content = attributes
187
- attributes = nil
188
- end
189
-
190
79
  VirtualDOM.node(
191
80
  tag_name,
192
81
  Component.sanitize_attributes(attributes),
@@ -2,16 +2,20 @@ require 'clearwater/virtual_dom/js/virtual_dom.js'
2
2
 
3
3
  module VirtualDOM
4
4
  def self.node(tag_name, attributes=nil, content=nil)
5
- content = sanitize_content(content)
6
- attributes = HashUtils.camelize_keys(attributes).to_n
7
- `virtualDom.h(tag_name, attributes, content)`
5
+ %x{
6
+ return virtualDom.h(
7
+ tag_name,
8
+ #{HashUtils.camelized_native(attributes)},
9
+ #{sanitize_content(content)}
10
+ );
11
+ }
8
12
  end
9
13
 
10
14
  def self.svg(tag_name, attributes=nil, content=nil)
11
15
  %x{
12
16
  return virtualDom.svg(
13
17
  tag_name,
14
- #{HashUtils.camelize_keys(attributes).to_n},
18
+ #{HashUtils.camelized_native(attributes)},
15
19
  #{sanitize_content(content)}
16
20
  );
17
21
  }
@@ -67,31 +71,27 @@ module VirtualDOM
67
71
 
68
72
  module StringUtils
69
73
  def self.camelize string
70
- %x{
71
- return string.replace(/_(\w)/g, function(full_match, character_match) {
72
- return character_match.toUpperCase();
73
- })
74
- }
74
+ `string.replace(/_(\w)/g, self.$_camelize_handler)`
75
+ end
76
+
77
+ def self._camelize_handler _, character_match
78
+ `character_match.toUpperCase()`
75
79
  end
76
80
  end
77
81
 
78
82
  module HashUtils
79
- def self.camelize_keys(hash)
80
- return hash unless hash.is_a? Hash
83
+ def self.camelized_native hash
84
+ return hash.to_n unless `!!hash.$$is_hash`
81
85
 
82
- camelized = {}
83
- hash.each do |k, v|
84
- key = StringUtils.camelize(k)
85
- value = if v.class == Hash
86
- camelize_keys(v)
87
- else
88
- v
89
- end
90
-
91
- camelized[key] = value
92
- end
93
-
94
- camelized
86
+ %x{
87
+ var v, keys = #{hash.keys}, key, js_obj = {};
88
+ for(var index = 0; index < keys.length; index++) {
89
+ key = keys[index];
90
+ v = #{hash[`key`]};
91
+ js_obj[#{StringUtils.camelize(`key`)}] = v.$$is_hash ? self.$camelized_native(v) : v
92
+ }
93
+ return js_obj;
94
+ }
95
95
  end
96
96
  end
97
97
  end
@@ -0,0 +1,117 @@
1
+ module Clearwater
2
+ module Component
3
+ HTML_TAGS = %w(
4
+ a
5
+ abbr
6
+ address
7
+ area
8
+ article
9
+ aside
10
+ audio
11
+ b
12
+ base
13
+ bdi
14
+ bdo
15
+ blockquote
16
+ body
17
+ br
18
+ button
19
+ canvas
20
+ caption
21
+ cite
22
+ code
23
+ col
24
+ colgroup
25
+ command
26
+ data
27
+ datalist
28
+ dd
29
+ del
30
+ details
31
+ dfn
32
+ dialog
33
+ div
34
+ dl
35
+ dt
36
+ em
37
+ embed
38
+ fieldset
39
+ figcaption
40
+ figure
41
+ footer
42
+ form
43
+ h1
44
+ h2
45
+ h3
46
+ h4
47
+ h5
48
+ h6
49
+ head
50
+ header
51
+ hgroup
52
+ hr
53
+ html
54
+ i
55
+ iframe
56
+ img
57
+ input
58
+ ins
59
+ kbd
60
+ keygen
61
+ label
62
+ legend
63
+ li
64
+ link
65
+ main
66
+ map
67
+ mark
68
+ menu
69
+ meta
70
+ meter
71
+ nav
72
+ noscript
73
+ object
74
+ ol
75
+ optgroup
76
+ option
77
+ output
78
+ p
79
+ param
80
+ pre
81
+ progress
82
+ q
83
+ rp
84
+ rt
85
+ ruby
86
+ s
87
+ samp
88
+ script
89
+ section
90
+ select
91
+ small
92
+ source
93
+ span
94
+ strong
95
+ style
96
+ sub
97
+ summary
98
+ sup
99
+ table
100
+ tbody
101
+ td
102
+ textarea
103
+ tfoot
104
+ th
105
+ thead
106
+ time
107
+ title
108
+ tr
109
+ track
110
+ u
111
+ ul
112
+ var
113
+ video
114
+ wbr
115
+ )
116
+ end
117
+ end
@@ -9,6 +9,12 @@ module Clearwater
9
9
  @key = options.fetch(:key)
10
10
  @target = options.fetch(:target)
11
11
  @parent = options.fetch(:parent)
12
+
13
+ if `#@target.type === 'Thunk' && typeof #@target.render === 'function'`
14
+ warn "Route '#{key}' points to a cached component. Cached " +
15
+ "components must not be persistent components, such as " +
16
+ "application roots or routing targets."
17
+ end
12
18
  end
13
19
 
14
20
  def route *args, &block
@@ -6,9 +6,13 @@ module Clearwater
6
6
  attr_accessor :application
7
7
 
8
8
  def initialize options={}, &block
9
- @window = options.fetch(:window) { Bowser.window }
10
- @location = options.fetch(:location) { window.location }
11
- @history = options.fetch(:history) { window.history }
9
+ if RUBY_ENGINE == 'opal'
10
+ @window = options.fetch(:window) { Bowser.window }
11
+ @location = options.fetch(:location) { window.location }
12
+ @history = options.fetch(:history) { window.history }
13
+ else
14
+ @location = options.fetch(:location)
15
+ end
12
16
  @routes = RouteCollection.new(self)
13
17
  @application = options[:application]
14
18
 
@@ -20,7 +24,7 @@ module Clearwater
20
24
  end
21
25
 
22
26
  def routes_for_path path
23
- parts = path.split("/").reject(&:empty?)
27
+ parts = get_path_parts(path)
24
28
  @routes[parts]
25
29
  end
26
30
 
@@ -36,8 +40,8 @@ module Clearwater
36
40
  end
37
41
 
38
42
  def params path=current_path
39
- path_parts = path.split("/").reject(&:empty?)
40
- canonical_parts = canonical_path_for_path(path).split("/").reject(&:empty?)
43
+ path_parts = get_path_parts(path)
44
+ canonical_parts = get_path_parts(canonical_path_for_path(path))
41
45
 
42
46
  canonical_parts.each_with_index.reduce({}) { |params, (part, index)|
43
47
  if part.start_with? ":"
@@ -109,6 +113,10 @@ module Clearwater
109
113
 
110
114
  private
111
115
 
116
+ def get_path_parts path
117
+ path.split("/").reject(&:empty?)
118
+ end
119
+
112
120
  def render_application
113
121
  if application && application.component
114
122
  application.component.call
@@ -1,4 +1,6 @@
1
+ require 'spec_helper'
1
2
  require 'clearwater/black_box_node'
3
+ require 'clearwater/component'
2
4
 
3
5
  module Clearwater
4
6
  describe BlackBoxNode do
@@ -6,59 +8,14 @@ module Clearwater
6
8
  Class.new do
7
9
  include Clearwater::BlackBoxNode
8
10
 
9
- attr_reader :last_update
10
-
11
11
  def node
12
- VirtualDOM.node :span, { id: 'foo' }, ['hi']
13
- end
14
-
15
- def mount node
16
- @mounted = true
17
- end
18
-
19
- def update
20
- @last_update = Time.now
21
- end
22
-
23
- def unmount
24
- @mounted = false
25
- end
26
-
27
- def mounted?
28
- !!@mounted
12
+ Clearwater::Component.div({ id: 'foo' }, 'hi')
29
13
  end
30
14
  end.new
31
15
  }
32
- let(:renderable) { BlackBoxNode::Renderable.new(object) }
33
-
34
- it 'has the special type of "Widget"' do
35
- r = renderable
36
- expect(`r.type`).to eq 'Widget'
37
- end
38
-
39
- it 'uses the delegate node to render into the DOM' do
40
- r = renderable
41
- expect(`#{renderable.create_element}.native.outerHTML`).to eq '<span id="foo">hi</span>'
42
- end
43
-
44
- it 'calls mount when inserted into the DOM' do
45
- r = renderable
46
- `r.init()`
47
- expect(object).to be_mounted
48
- end
49
-
50
- it 'calls unmount when removed from the DOM' do
51
- r = renderable
52
- `r.init()`
53
- `r.destroy()`
54
- expect(object).not_to be_mounted
55
- end
56
-
57
- it 'calls update when updated in the DOM' do
58
- r = renderable
59
- `r.update({})`
60
16
 
61
- expect(object.last_update).not_to be_nil
17
+ it 'just renders the specified node' do
18
+ expect(object.to_s).to eq '<div id="foo">hi</div>'
62
19
  end
63
20
  end
64
21
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require_relative '../../lib/clearwater/component'
3
+
4
+ module Clearwater
5
+ RSpec.describe Component do
6
+ let(:component) { Class.new { include Clearwater::Component }.new }
7
+
8
+ it 'generates html' do
9
+ html = component.div({ id: 'foo', class_name: 'bar' }, [
10
+ component.p("baz"),
11
+ ]).to_s
12
+
13
+ expect(html).to eq('<div id="foo" class="bar"><p>baz</p></div>')
14
+ end
15
+
16
+ it 'converts styles into strings' do
17
+ html = component.div({
18
+ style: {
19
+ font_size: '24px',
20
+ padding: '3px',
21
+ }
22
+ }, "Hello world!").to_s
23
+
24
+ expect(html).to eq('<div style="font-size:24px;padding:3px">Hello world!</div>')
25
+ end
26
+
27
+ it 'removes DOMReference attributes' do
28
+ html = component.div({
29
+ ref: DOMReference.new,
30
+ }, 'Hello World!').to_s
31
+
32
+ expect(html).to eq('<div>Hello World!</div>')
33
+ end
34
+
35
+ describe 'content sanitization' do
36
+ it 'sanitizes content strings, but not elements' do
37
+ html = component.div(component.p('<em>hi</em>')).to_s
38
+
39
+ expect(html).to eq '<div><p>&lt;em>hi&lt;/em></p></div>'
40
+ end
41
+ end
42
+ end
43
+ end
@@ -4,12 +4,8 @@ module Clearwater
4
4
  describe DOMReference do
5
5
  let(:ref) { DOMReference.new }
6
6
 
7
- it 'delegates to the DOM node passed in on mount' do
8
- r = ref
9
-
10
- `r.hook({ value: 'hi' })`
11
-
12
- expect(r.value).to eq 'hi'
7
+ it 'sanitizes to an empty string' do
8
+ expect(ref.to_s).to eq ''
13
9
  end
14
10
  end
15
11
  end
@@ -0,0 +1 @@
1
+ $:.unshift 'shared'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clearwater
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta5
4
+ version: 1.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Gaskins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-06 00:00:00.000000000 Z
11
+ date: 2016-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opal
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.1.2
33
+ version: 0.1.5
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.1.2
40
+ version: 0.1.5
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.5.0.beta2
61
+ version: 0.5.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.5.0.beta2
68
+ version: 0.5.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.3'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -102,6 +116,12 @@ extensions: []
102
116
  extra_rdoc_files: []
103
117
  files:
104
118
  - lib/clearwater.rb
119
+ - lib/clearwater/application.rb
120
+ - lib/clearwater/black_box_node.rb
121
+ - lib/clearwater/cached_render.rb
122
+ - lib/clearwater/component.rb
123
+ - lib/clearwater/dom_reference.rb
124
+ - lib/clearwater/link.rb
105
125
  - lib/clearwater/version.rb
106
126
  - opal/clearwater.rb
107
127
  - opal/clearwater/application.rb
@@ -111,18 +131,17 @@ files:
111
131
  - opal/clearwater/component.rb
112
132
  - opal/clearwater/dom_reference.rb
113
133
  - opal/clearwater/link.rb
114
- - opal/clearwater/router.rb
115
- - opal/clearwater/router/route.rb
116
- - opal/clearwater/router/route_collection.rb
117
134
  - opal/clearwater/svg_component.rb
118
135
  - opal/clearwater/virtual_dom.rb
119
136
  - opal/clearwater/virtual_dom/js/virtual_dom.js
120
- - spec/clearwater/application_spec.rb
137
+ - shared/clearwater/component/html_tags.rb
138
+ - shared/clearwater/router.rb
139
+ - shared/clearwater/router/route.rb
140
+ - shared/clearwater/router/route_collection.rb
121
141
  - spec/clearwater/black_box_node_spec.rb
122
- - spec/clearwater/cached_render_spec.rb
142
+ - spec/clearwater/component_spec.rb
123
143
  - spec/clearwater/dom_reference_spec.rb
124
- - spec/clearwater/router_spec.rb
125
- - spec/component_spec.rb
144
+ - spec/spec_helper.rb
126
145
  homepage: https://clearwater-rb.github.io/
127
146
  licenses:
128
147
  - MIT
@@ -131,6 +150,7 @@ post_install_message:
131
150
  rdoc_options: []
132
151
  require_paths:
133
152
  - lib
153
+ - shared
134
154
  required_ruby_version: !ruby/object:Gem::Requirement
135
155
  requirements:
136
156
  - - ">="
@@ -143,15 +163,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
163
  version: 1.3.1
144
164
  requirements: []
145
165
  rubyforge_project:
146
- rubygems_version: 2.5.1
166
+ rubygems_version: 2.4.8
147
167
  signing_key:
148
168
  specification_version: 4
149
169
  summary: Front-end Ruby web framework for fast, reasonable, and composable applications
150
170
  test_files:
151
- - spec/clearwater/application_spec.rb
152
171
  - spec/clearwater/black_box_node_spec.rb
153
- - spec/clearwater/cached_render_spec.rb
172
+ - spec/clearwater/component_spec.rb
154
173
  - spec/clearwater/dom_reference_spec.rb
155
- - spec/clearwater/router_spec.rb
156
- - spec/component_spec.rb
157
- has_rdoc:
174
+ - spec/spec_helper.rb
@@ -1,62 +0,0 @@
1
- require 'clearwater'
2
- require 'clearwater/svg_component'
3
- require 'bowser'
4
-
5
- module Clearwater
6
- RSpec.describe Application do
7
- let(:app) {
8
- Application.new(
9
- component: component,
10
- element: element,
11
- )
12
- }
13
- let(:component) {
14
- $svg_component = self.svg_component
15
- Class.new do
16
- include Clearwater::Component
17
-
18
- def render
19
- div([
20
- p({ class_name: 'foo' }, 'Hello world'),
21
- $svg_component,
22
- ])
23
- end
24
- end.new
25
- }
26
- let(:svg_component) {
27
- Class.new do
28
- include Clearwater::SVGComponent
29
-
30
- def render
31
- svg({ class: 'mysvg', marker_height: 10, marker_end: "url(#arrow)" }, [
32
- circle(cx: 50, cy: 50, r: 30),
33
- ])
34
- end
35
- end.new
36
- }
37
- let(:element) { Bowser.document.create_element('div') }
38
-
39
- it 'renders to the specified element' do
40
- app.perform_render
41
-
42
- expect(element.inner_html).to eq '<div><p class="foo">Hello world</p><svg class="mysvg" markerHeight="10" marker-end="url(#arrow)"><circle cx="50" cy="50" r="30"></circle></svg></div>'
43
- end
44
-
45
- it 'calls queued blocks after rendering' do
46
- i = 1
47
- app.on_render << proc { i += 1 }
48
- app.on_render << proc { i += 1 }
49
-
50
- app.perform_render
51
- expect(i).to eq 3
52
- end
53
-
54
- it 'empties the block queue after rendering' do
55
- app.on_render << proc { }
56
-
57
- app.perform_render
58
-
59
- expect(app.on_render).to be_empty
60
- end
61
- end
62
- end
@@ -1,46 +0,0 @@
1
- require 'clearwater/component'
2
- require 'clearwater/cached_render'
3
-
4
- module Clearwater
5
- describe CachedRender do
6
- let(:component_class) {
7
- Class.new do
8
- include Clearwater::Component
9
- include Clearwater::CachedRender
10
-
11
- def initialize value
12
- @value = value
13
- end
14
-
15
- def render
16
- @value.to_s
17
- end
18
- end
19
- }
20
- let(:value) { double }
21
- let(:component) { component_class.new(value) }
22
-
23
- it 'memoizes the return value of render' do
24
- component = component()
25
-
26
- expect(value).to receive(:to_s)
27
- %x{ component.render(component) }
28
-
29
- component.instance_exec { @vnode = VirtualDOM.node('div', 'howdy') }
30
- expect(value).not_to receive(:to_s)
31
-
32
- 2.times { `component.render(component)` }
33
- end
34
-
35
- it 'uses should_render? to determine whether to call render again' do
36
- component = component()
37
- def component.should_render?
38
- true
39
- end
40
-
41
- expect(value).to receive(:to_s).twice
42
-
43
- 2.times { `component.render(component)` }
44
- end
45
- end
46
- end
@@ -1,65 +0,0 @@
1
- require 'clearwater/router'
2
- require 'ostruct'
3
-
4
- module Clearwater
5
- RSpec.describe Router do
6
- let(:component_class) {
7
- Class.new do
8
- include Clearwater::Component
9
- end
10
- }
11
- let(:routed_component) { component_class.new }
12
- let!(:router) {
13
- component = routed_component
14
- Router.new do
15
- route 'articles' => component do
16
- route ':article_id' => component
17
- end
18
- end
19
- }
20
-
21
- it 'sets the router for a routed component' do
22
- expect(routed_component.router).to be router
23
- end
24
-
25
- it 'gets the params for a given path' do
26
- expect(router.params('/articles/foo')).to eq article_id: 'foo'
27
- end
28
-
29
- it 'gets the components for a given path' do
30
- expect(router.targets_for_path('/articles/1')).to eq [
31
- routed_component, routed_component
32
- ]
33
-
34
- expect(router.targets_for_path('/articles')).to eq [routed_component]
35
- end
36
-
37
- it 'gets the current path' do
38
- location = OpenStruct.new(path: '/foo')
39
- router = Router.new(location: location)
40
-
41
- expect(router.current_path).to eq '/foo'
42
-
43
- location.path = '/bar'
44
-
45
- expect(router.current_path).to eq '/bar'
46
- end
47
-
48
- it 'gets the params from the path' do
49
- expect(router.params('/articles/123')).to eq({ article_id: '123' })
50
- end
51
-
52
- it 'gets params with a namespace' do
53
- component = routed_component
54
- router = Router.new do
55
- namespace 'clearwater'
56
-
57
- route 'articles' => component do
58
- route ':article_id' => component
59
- end
60
- end
61
-
62
- expect(router.params('/clearwater/articles/123')).to eq({ article_id: '123' })
63
- end
64
- end
65
- end
@@ -1,57 +0,0 @@
1
- require 'clearwater/component'
2
-
3
- module Clearwater
4
- RSpec.describe Component do
5
- let(:component_class) {
6
- Class.new do
7
- include Clearwater::Component
8
- end
9
- }
10
- let(:component) { component_class.new }
11
-
12
- it 'provides a default render method' do
13
- expect(component.render).to be_nil
14
- end
15
-
16
- Component::HTML_TAGS.each do |tag|
17
- it "provides helpers for `#{tag}` elements" do
18
- expect(`#{component.send(tag)}.tagName`).to eq tag.upcase
19
- end
20
- end
21
-
22
- it 'sanitizes element attributes' do
23
- attributes = Component.sanitize_attributes({
24
- class: 'foo',
25
- onclick: proc { |event| expect(event).to be_a Bowser::Event },
26
- })
27
-
28
- # Renames :class to :class_name
29
- expect(attributes[:class_name]).to eq 'foo'
30
-
31
- # Wraps yielded events in a Bowser::Event
32
- attributes[:onclick].call(`document.createEvent('MouseEvent')`)
33
- end
34
-
35
- describe 'sanitizing content' do
36
- it 'sanitizes components by calling `render`' do
37
- allow(component).to receive(:render) { 'foo' }
38
- expect(Component.sanitize_content(component)).to eq 'foo'
39
- end
40
-
41
- it 'sanitizes arrays by sanitizing each element' do
42
- allow(component).to receive(:render) { 'foo' }
43
- expect(Component.sanitize_content([component, nil, 1])).to eq ['foo', nil, 1]
44
- end
45
- end
46
-
47
- it 'retrieves params from the router' do
48
- router = double('Router')
49
- params = { article_id: 123 }
50
- allow(router).to receive(:params) { params }
51
- allow(router).to receive(:current_path) { '/articles/123' }
52
- component.router = router
53
-
54
- expect(component.params).to eq params
55
- end
56
- end
57
- end