browserio 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -0
- data/Gemfile +0 -2
- data/LICENSE.txt +1 -1
- data/README.md +5 -23
- data/Rakefile +1 -8
- data/bin/bio +36 -0
- data/browserio.gemspec +9 -14
- data/lib/browserio.rb +3 -187
- data/lib/browserio/cli.rb +40 -0
- data/lib/browserio/version.rb +1 -1
- metadata +34 -125
- data/lib/browserio/component.rb +0 -326
- data/lib/browserio/config.rb +0 -120
- data/lib/browserio/dom.rb +0 -139
- data/lib/browserio/events.rb +0 -136
- data/lib/browserio/html.rb +0 -29
- data/lib/browserio/opal.rb +0 -18
- data/lib/browserio/plugins/form.rb +0 -343
- data/lib/browserio/plugins/history.rb +0 -92
- data/lib/browserio/plugins/location.rb +0 -78
- data/lib/browserio/plugins/pjax.rb +0 -65
- data/lib/browserio/plugins/validations.rb +0 -251
- data/lib/browserio/utilis/blank.rb +0 -133
- data/lib/browserio/utilis/element.rb +0 -23
- data/lib/browserio/utilis/hash.rb +0 -77
- data/lib/browserio/utilis/indifferent_hash.rb +0 -209
- data/lib/browserio/utilis/methods.rb +0 -25
- data/lib/browserio/utilis/nokogiri.rb +0 -44
- data/lib/browserio/utilis/titleize.rb +0 -97
- data/lib/browserio/utilis/try.rb +0 -106
- data/lib/roda/plugins/browserio.rb +0 -88
- data/test/dummy/app.rb +0 -34
- data/test/dummy/components/bar.rb +0 -16
- data/test/dummy/components/root.rb +0 -39
- data/test/dummy/config.ru +0 -6
- data/test/dummy/forms/foo.rb +0 -6
- data/test/test.js +0 -59
- data/test/test_basic_component.rb +0 -34
- data/test/test_browserio.rb +0 -13
- data/test/test_helper.rb +0 -38
@@ -1,44 +0,0 @@
|
|
1
|
-
module Nokogiri
|
2
|
-
module XML
|
3
|
-
class NodeSet
|
4
|
-
# fix: this is really shity
|
5
|
-
# alias_method :original_to_html, :to_html
|
6
|
-
# def to_html *args
|
7
|
-
# original_to_html(*args).gsub('%7B', "{").gsub('%7D', "}")
|
8
|
-
# end
|
9
|
-
end
|
10
|
-
class Node
|
11
|
-
# fix: this is really shity
|
12
|
-
# alias_method :original_to_html, :to_html
|
13
|
-
# def to_html *args
|
14
|
-
# original_to_html(*args).gsub('%7B', "{").gsub('%7D', "}")
|
15
|
-
# end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def coerce data # :nodoc:
|
20
|
-
if data.class.to_s == 'BrowserIO::DOM'
|
21
|
-
data = data.dom
|
22
|
-
end
|
23
|
-
|
24
|
-
case data
|
25
|
-
when XML::NodeSet
|
26
|
-
return data
|
27
|
-
when XML::DocumentFragment
|
28
|
-
return data.children
|
29
|
-
when String
|
30
|
-
return fragment(data).children
|
31
|
-
when Document, XML::Attr
|
32
|
-
# unacceptable
|
33
|
-
when XML::Node
|
34
|
-
return data
|
35
|
-
end
|
36
|
-
|
37
|
-
raise ArgumentError, <<-EOERR
|
38
|
-
Requires a Node, NodeSet or String argument, and cannot accept a #{data.class}.
|
39
|
-
(You probably want to select a node from the Document with at() or search(), or create a new Node via Node.new().)
|
40
|
-
EOERR
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
# Adds String#titleize for creating properly capitalized titles.
|
3
|
-
# It can be called as Titleize.titleize or "a string".titleize.
|
4
|
-
#
|
5
|
-
# titlecase is included as an alias for titleize.
|
6
|
-
#
|
7
|
-
# If loaded in a Rails environment, it modifies Inflector.titleize.
|
8
|
-
module Titleize
|
9
|
-
SMALL_WORDS = %w{a an and as at but by en for if in of on or the to v v. via vs vs.}
|
10
|
-
|
11
|
-
extend self
|
12
|
-
|
13
|
-
# Capitalizes most words to create a nicer looking title string.
|
14
|
-
#
|
15
|
-
# The list of "small words" which are not capped comes from
|
16
|
-
# the New York Times Manual of Style, plus 'vs' and 'v'.
|
17
|
-
#
|
18
|
-
# "notes on a scandal" # => "Notes on a Scandal"
|
19
|
-
# "the good german" # => "The Good German"
|
20
|
-
def titleize(title)
|
21
|
-
title = title.dup
|
22
|
-
title.downcase! unless title[/[[:lower:]]/] # assume all-caps need fixing
|
23
|
-
|
24
|
-
phrases(title).map do |phrase|
|
25
|
-
words = phrase.split
|
26
|
-
words.map do |word|
|
27
|
-
def word.capitalize
|
28
|
-
# like String#capitalize, but it starts with the first letter
|
29
|
-
self.sub(/[[:alpha:]].*/) {|subword| subword.capitalize}
|
30
|
-
end
|
31
|
-
|
32
|
-
case word
|
33
|
-
when /[[:alpha:]]\.[[:alpha:]]/ # words with dots in, like "example.com"
|
34
|
-
word
|
35
|
-
when /[-‑]/ # hyphenated word (regular and non-breaking)
|
36
|
-
word.split(/([-‑])/).map do |part|
|
37
|
-
SMALL_WORDS.include?(part) ? part : part.capitalize
|
38
|
-
end.join
|
39
|
-
when /^[[:alpha:]].*[[:upper:]]/ # non-first letter capitalized already
|
40
|
-
word
|
41
|
-
when /^[[:digit:]]/ # first character is a number
|
42
|
-
word
|
43
|
-
when words.first, words.last
|
44
|
-
word.capitalize
|
45
|
-
when *(SMALL_WORDS + SMALL_WORDS.map {|small| small.capitalize })
|
46
|
-
word.downcase
|
47
|
-
else
|
48
|
-
word.capitalize
|
49
|
-
end
|
50
|
-
end.join(" ")
|
51
|
-
end.join(" ")
|
52
|
-
end
|
53
|
-
|
54
|
-
# Splits a title into an array based on punctuation.
|
55
|
-
#
|
56
|
-
# "simple title" # => ["simple title"]
|
57
|
-
# "more complicated: titling" # => ["more complicated:", "titling"]
|
58
|
-
def phrases(title)
|
59
|
-
phrases = title.scan(/.+?(?:[:.;?!] |$)/).map {|phrase| phrase.strip }
|
60
|
-
|
61
|
-
# rejoin phrases that were split on the '.' from a small word
|
62
|
-
if phrases.size > 1
|
63
|
-
phrases[0..-2].each_with_index do |phrase, index|
|
64
|
-
if SMALL_WORDS.include?(phrase.split.last.downcase)
|
65
|
-
phrases[index] << " " + phrases.slice!(index + 1)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
phrases
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class String
|
75
|
-
# Capitalizes most words to create a nicer looking title string.
|
76
|
-
#
|
77
|
-
# The list of "small words" which are not capped comes from
|
78
|
-
# the New York Times Manual of Style, plus 'vs' and 'v'.
|
79
|
-
#
|
80
|
-
# titleize is also aliased as titlecase.
|
81
|
-
#
|
82
|
-
# "notes on a scandal" # => "Notes on a Scandal"
|
83
|
-
# "the good german" # => "The Good German"
|
84
|
-
def titleize(opts={})
|
85
|
-
# if defined? ActiveSupport
|
86
|
-
# ActiveSupport::Inflector.titleize(self, opts)
|
87
|
-
# else
|
88
|
-
Titleize.titleize(self)
|
89
|
-
# end
|
90
|
-
end
|
91
|
-
alias_method :titlecase, :titleize
|
92
|
-
|
93
|
-
def titleize!
|
94
|
-
replace(titleize)
|
95
|
-
end
|
96
|
-
alias_method :titlecase!, :titleize!
|
97
|
-
end
|
data/lib/browserio/utilis/try.rb
DELETED
@@ -1,106 +0,0 @@
|
|
1
|
-
class Object
|
2
|
-
# Invokes the public method whose name goes as first argument just like
|
3
|
-
# +public_send+ does, except that if the receiver does not respond to it the
|
4
|
-
# call returns +nil+ rather than raising an exception.
|
5
|
-
#
|
6
|
-
# This method is defined to be able to write
|
7
|
-
#
|
8
|
-
# @person.try(:name)
|
9
|
-
#
|
10
|
-
# instead of
|
11
|
-
#
|
12
|
-
# @person.name if @person
|
13
|
-
#
|
14
|
-
# +try+ calls can be chained:
|
15
|
-
#
|
16
|
-
# @person.try(:spouse).try(:name)
|
17
|
-
#
|
18
|
-
# instead of
|
19
|
-
#
|
20
|
-
# @person.spouse.name if @person && @person.spouse
|
21
|
-
#
|
22
|
-
# +try+ will also return +nil+ if the receiver does not respond to the method:
|
23
|
-
#
|
24
|
-
# @person.try(:non_existing_method) # => nil
|
25
|
-
#
|
26
|
-
# instead of
|
27
|
-
#
|
28
|
-
# @person.non_existing_method if @person.respond_to?(:non_existing_method) # => nil
|
29
|
-
#
|
30
|
-
# +try+ returns +nil+ when called on +nil+ regardless of whether it responds
|
31
|
-
# to the method:
|
32
|
-
#
|
33
|
-
# nil.try(:to_i) # => nil, rather than 0
|
34
|
-
#
|
35
|
-
# Arguments and blocks are forwarded to the method if invoked:
|
36
|
-
#
|
37
|
-
# @posts.try(:each_slice, 2) do |a, b|
|
38
|
-
# ...
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# The number of arguments in the signature must match. If the object responds
|
42
|
-
# to the method the call is attempted and +ArgumentError+ is still raised
|
43
|
-
# in case of argument mismatch.
|
44
|
-
#
|
45
|
-
# If +try+ is called without arguments it yields the receiver to a given
|
46
|
-
# block unless it is +nil+:
|
47
|
-
#
|
48
|
-
# @person.try do |p|
|
49
|
-
# ...
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# You can also call try with a block without accepting an argument, and the block
|
53
|
-
# will be instance_eval'ed instead:
|
54
|
-
#
|
55
|
-
# @person.try { upcase.truncate(50) }
|
56
|
-
#
|
57
|
-
# Please also note that +try+ is defined on +Object+. Therefore, it won't work
|
58
|
-
# with instances of classes that do not have +Object+ among their ancestors,
|
59
|
-
# like direct subclasses of +BasicObject+. For example, using +try+ with
|
60
|
-
# +SimpleDelegator+ will delegate +try+ to the target instead of calling it on
|
61
|
-
# the delegator itself.
|
62
|
-
def try(*a, &b)
|
63
|
-
try!(*a, &b) if a.empty? || respond_to?(a.first)
|
64
|
-
end
|
65
|
-
|
66
|
-
# Same as #try, but raises a NoMethodError exception if the receiver is
|
67
|
-
# not +nil+ and does not implement the tried method.
|
68
|
-
#
|
69
|
-
# "a".try!(:upcase) # => "A"
|
70
|
-
# nil.try!(:upcase) # => nil
|
71
|
-
# 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Fixnum
|
72
|
-
def try!(*a, &b)
|
73
|
-
if a.empty? && block_given?
|
74
|
-
if b.arity.zero?
|
75
|
-
instance_eval(&b)
|
76
|
-
else
|
77
|
-
yield self
|
78
|
-
end
|
79
|
-
else
|
80
|
-
public_send(*a, &b)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class NilClass
|
86
|
-
# Calling +try+ on +nil+ always returns +nil+.
|
87
|
-
# It becomes especially helpful when navigating through associations that may return +nil+.
|
88
|
-
#
|
89
|
-
# nil.try(:name) # => nil
|
90
|
-
#
|
91
|
-
# Without +try+
|
92
|
-
# @person && @person.children.any? && @person.children.first.name
|
93
|
-
#
|
94
|
-
# With +try+
|
95
|
-
# @person.try(:children).try(:first).try(:name)
|
96
|
-
def try(*args)
|
97
|
-
nil
|
98
|
-
end
|
99
|
-
|
100
|
-
# Calling +try!+ on +nil+ always returns +nil+.
|
101
|
-
#
|
102
|
-
# nil.try!(:name) # => nil
|
103
|
-
def try!(*args)
|
104
|
-
nil
|
105
|
-
end
|
106
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
class Roda
|
2
|
-
module RodaPlugins
|
3
|
-
module BrowserIO
|
4
|
-
def self.configure(app, opts = {})
|
5
|
-
if app.opts[:browserio]
|
6
|
-
app.opts[:browserio].merge!(opts)
|
7
|
-
else
|
8
|
-
app.opts[:browserio] = opts.dup
|
9
|
-
end
|
10
|
-
|
11
|
-
opts = app.opts[:browserio]
|
12
|
-
|
13
|
-
opts.each do |k, v|
|
14
|
-
case k.to_s
|
15
|
-
when 'plugins'
|
16
|
-
v.each { |p| ::BrowserIO.config.plugin p }
|
17
|
-
when 'scope'
|
18
|
-
::BrowserIO.config.scope v.new
|
19
|
-
else
|
20
|
-
::BrowserIO.config.send(k, v)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
module InstanceMethods
|
26
|
-
def bio(*args)
|
27
|
-
args << { scope: self }
|
28
|
-
::BrowserIO[*args]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
module RequestClassMethods
|
33
|
-
def bio_route_regex
|
34
|
-
%r{#{roda_class.opts[:browserio][:assets_url]}/(.*)\.(.*)$}
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
module RequestMethods
|
39
|
-
def browserio
|
40
|
-
on self.class.bio_route_regex do |component, ext|
|
41
|
-
case ext
|
42
|
-
when 'map'
|
43
|
-
::BrowserIO.source_map component
|
44
|
-
when 'rb'
|
45
|
-
if component =~ /^browserio/
|
46
|
-
path = ::BrowserIO.opts.file_path.gsub(/\/browserio.rb$/, '')
|
47
|
-
File.read("#{path}/#{component}.rb")
|
48
|
-
else
|
49
|
-
File.read("#{ROOT_PATH}/#{component}.rb")
|
50
|
-
end
|
51
|
-
when 'call'
|
52
|
-
body = scope.request.body.read
|
53
|
-
data = scope.request.params
|
54
|
-
|
55
|
-
begin
|
56
|
-
data.merge!(body ? JSON.parse(body) : {})
|
57
|
-
rescue
|
58
|
-
# can't be parsed by json
|
59
|
-
end
|
60
|
-
|
61
|
-
data = data.indifferent
|
62
|
-
name = data.delete(:name)
|
63
|
-
method_called = data.delete(:method_called)
|
64
|
-
method_args = data.delete(:method_args)
|
65
|
-
|
66
|
-
res = scope.bio(name, data).send(method_called, *method_args)
|
67
|
-
|
68
|
-
scope.response.headers["BIO-CSRF-TOKEN"] = scope.csrf_token if scope.methods.include? :csrf_token
|
69
|
-
|
70
|
-
if res.is_a? Hash
|
71
|
-
scope.response.headers["Content-Type"] = 'application/json; charset=UTF-8'
|
72
|
-
res = res.to_json
|
73
|
-
else
|
74
|
-
res = res.to_s
|
75
|
-
end
|
76
|
-
|
77
|
-
res
|
78
|
-
else
|
79
|
-
"#{::BrowserIO.javascript(component)}\n//# sourceMappingURL=/assets/bio/#{component}.map"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
register_plugin(:browserio, BrowserIO)
|
87
|
-
end
|
88
|
-
end
|
data/test/dummy/app.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
require 'browserio'
|
2
|
-
require 'roda'
|
3
|
-
|
4
|
-
require 'pry'
|
5
|
-
require 'awesome_print'
|
6
|
-
|
7
|
-
ROOT_PATH = File.dirname(__FILE__)
|
8
|
-
|
9
|
-
class DummyApp < Roda
|
10
|
-
plugin :assets, {
|
11
|
-
group_subdirs: false,
|
12
|
-
path: ROOT_PATH,
|
13
|
-
css_dir: '',
|
14
|
-
js_dir: '',
|
15
|
-
js: [ 'bio/browserio.js' ]
|
16
|
-
}
|
17
|
-
|
18
|
-
plugin :browserio, {
|
19
|
-
scope: self,
|
20
|
-
assets_url: 'assets/bio',
|
21
|
-
plugins: [:form]
|
22
|
-
}
|
23
|
-
|
24
|
-
route do |r|
|
25
|
-
r.browserio
|
26
|
-
|
27
|
-
r.root do
|
28
|
-
bio(:root, :js).display
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
Dir["#{ROOT_PATH}/forms/*.rb"].sort.each { |file| require file }
|
34
|
-
Dir["#{ROOT_PATH}/components/*.rb"].sort.each { |file| require file }
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require_relative 'root' unless RUBY_ENGINE == 'opal'
|
2
|
-
|
3
|
-
class DummyApp
|
4
|
-
class BarComponent < BrowserIO::Component
|
5
|
-
config.name :bar
|
6
|
-
config.requires :root
|
7
|
-
|
8
|
-
def moo
|
9
|
-
'cow'
|
10
|
-
end
|
11
|
-
|
12
|
-
on :clicked_foo, for: :root do
|
13
|
-
dom.find('body').append moo
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
class DummyApp
|
2
|
-
class RootComponent < BrowserIO::Component
|
3
|
-
config.name :root
|
4
|
-
config.html <<-HTML
|
5
|
-
<!DOCTYPE html>
|
6
|
-
<html>
|
7
|
-
<head>
|
8
|
-
<script src="//code.jquery.com/jquery-1.11.2.js"></script>
|
9
|
-
</head>
|
10
|
-
<body>
|
11
|
-
<div id='foo'>bar</div>
|
12
|
-
</body>
|
13
|
-
</html>
|
14
|
-
HTML
|
15
|
-
config.dom do
|
16
|
-
dom.find('body') << assets(:js)
|
17
|
-
end
|
18
|
-
config.requires :bar, :foo_form
|
19
|
-
|
20
|
-
def display
|
21
|
-
if server?
|
22
|
-
dom
|
23
|
-
else
|
24
|
-
el = Element['<div>']
|
25
|
-
el.html 'foo'
|
26
|
-
dom.find('#foo').before el
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
on :ready do
|
31
|
-
puts 'dom ready'
|
32
|
-
end
|
33
|
-
|
34
|
-
on :click, '#foo' do |el|
|
35
|
-
el.after '<div>bar</div>'
|
36
|
-
trigger :clicked_foo
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
data/test/dummy/config.ru
DELETED