browserio 0.0.1 → 0.0.2

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: 405d7d3fe522f2989d67f63534a454860f8e6510
4
- data.tar.gz: d1a294cb773fa702087f0fb0a11b9977dc9fe345
3
+ metadata.gz: 48125d1757fc1b32e8551a1f303debbd8091a1bf
4
+ data.tar.gz: ef4f1f24a520017fc29568b731bce9741fe1ff70
5
5
  SHA512:
6
- metadata.gz: f112750279ff5234ef7ba65746fc00d8eb25e84c96b11e5c40e9d65dff1d047da5e5246a6de45b6fb88edd8f8ef9f10044429dce8edf6d8d5609719f457b1d4d
7
- data.tar.gz: be5f11303c2f9259f3ccc7c5372dd71aa0765418699c855d130ebc810e182bbf9cfd42967464c22d38372f351f3e34c545183521f84a7044339a3fc4a97fe63b
6
+ metadata.gz: 52f519118b696c1d83d4645261ef1f1166082a728ace2563271f4d1f4a1fb8380f7e0e9be8a3a5856b87ac57028c37debf525d33708d66d824acc44aed3085e8
7
+ data.tar.gz: 158724dbc60016ef7c4f21704e748a0c1c994476cab072847bdb98e4d6776beb3914252b7fd07419e898b3b3790b8a2faaa90d2a2f8163975adc095a515ffb34
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in BrowserIO.gemspec
4
4
  gemspec
5
+
6
+ gem 'opal', github: 'opal/opal'
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 cj
1
+ Copyright (c) 2015 cj
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # BrowserIO
2
2
 
3
- TODO: Write a gem description
3
+ Components for Ruby.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'BrowserIO'
10
+ gem 'browserio'
11
11
  ```
12
12
 
13
13
  And then execute:
@@ -16,11 +16,29 @@ And then execute:
16
16
 
17
17
  Or install it yourself as:
18
18
 
19
- $ gem install BrowserIO
19
+ $ gem install browserio
20
20
 
21
- ## Usage
21
+ ## Basic Usage
22
22
 
23
- TODO: Write usage instructions here
23
+ ### Setup
24
+
25
+ class BasicComponent < BrowserIO::Component
26
+ setup do |config|
27
+ config.name :basic
28
+ end
29
+
30
+ def foo
31
+ 'bar'
32
+ end
33
+ end
34
+
35
+ ### Call
36
+
37
+ Browser[:basic].foo
38
+
39
+ ### Response
40
+
41
+ 'bar'
24
42
 
25
43
  ## Contributing
26
44
 
data/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
2
3
 
4
+ Rake::TestTask.new do |task|
5
+ task.libs << %w(test lib)
6
+ task.pattern = 'test/**/test_*.rb'
7
+ end
8
+
9
+ task default: :test
@@ -1,15 +1,15 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'browserio'
4
+ require 'browserio/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "browserio"
8
8
  spec.version = BrowserIO::VERSION
9
9
  spec.authors = ["cj"]
10
10
  spec.email = ["cjlazell@gmail.com"]
11
- spec.summary = %q{}
12
- spec.description = %q{}
11
+ spec.summary = %q{Components for the Browser and Server}
12
+ spec.description = %q{Components for the Browser and Server}
13
13
  spec.homepage = ""
14
14
  spec.license = "MIT"
15
15
 
@@ -18,7 +18,15 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "roda"
22
- spec.add_development_dependency "bundler", "~> 1.7"
23
- spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_runtime_dependency "opal", "~> 0.7.1"
22
+ spec.add_runtime_dependency "opal-jquery", "~> 0.3.0"
23
+ spec.add_runtime_dependency "nokogiri", '~> 1.6.6.2'
24
+
25
+ spec.add_development_dependency "pry"
26
+ spec.add_development_dependency "awesome_print"
27
+ spec.add_development_dependency "yard"
28
+ spec.add_development_dependency "phantomjs.rb"
29
+ spec.add_development_dependency 'minitest-line'
30
+ spec.add_development_dependency 'minitest-reporters'
31
+ spec.add_development_dependency 'roda'
24
32
  end
@@ -1,5 +1,185 @@
1
- require "roda"
1
+ require 'browserio/opal'
2
+ require 'browserio/version'
3
+ require 'browserio/utilis/indifferent_hash'
4
+ require 'browserio/utilis/hash'
5
+ require 'browserio/utilis/blank'
6
+ require 'browserio/utilis/methods'
7
+ require 'browserio/utilis/try'
8
+ require 'browserio/utilis/titleize'
9
+ require 'base64'
10
+ require 'nokogiri' unless RUBY_ENGINE == 'opal'
11
+ require 'browserio/html'
12
+ require 'browserio/dom'
13
+ require 'browserio/config'
14
+ require 'browserio/component'
2
15
 
3
- class BrowserIO < Roda
4
- VERSION = "0.0.1"
16
+ module BrowserIO
17
+ include Methods
18
+
19
+ class << self
20
+ # Used to call a component.
21
+ #
22
+ # @example
23
+ # Browser[:foo].bar
24
+ #
25
+ # @param name [String, Symbol, #to_s] The unique name given to a component.
26
+ # @return [BrowserIO::Component#method] Last line of the method called.
27
+ def [](name, *args)
28
+ component = components[name.to_sym]
29
+
30
+ component.klass.new(*args)
31
+ end
32
+
33
+ def components
34
+ @components ||= OpenStruct.new
35
+ end
36
+
37
+ if RUBY_ENGINE == 'ruby'
38
+ # Returns the build object for opal.
39
+ #
40
+ # @param path [String] require path to file to build.
41
+ # @return [String, Opal::Builder#build]
42
+ def build(path = 'browserio', options = {})
43
+ append_paths
44
+ Opal::Builder.build(path, options)
45
+ end
46
+
47
+ # Source maps for the javascript
48
+ def source_map(path = 'browserio', options = {})
49
+ build(path, options).source_map
50
+ end
51
+
52
+ # Append the correct paths to opal.
53
+ #
54
+ # @return [Array] List of opal paths.
55
+ def append_paths
56
+ @append_paths ||= begin
57
+ file = method(:components).source_location.first.sub('/browserio.rb', '')
58
+ BrowserIO::Opal.append_path file
59
+ BrowserIO::Opal.append_path Dir.pwd
60
+ end
61
+ end
62
+ end
63
+
64
+ # Return the opal javascript.
65
+ def javascript(name = 'browserio', options = {}, promise = false)
66
+ if server?
67
+ if name == 'browserio'
68
+ @bio_javascript ||= build(name, options).javascript
69
+ else
70
+ js = build(name, options).javascript
71
+ comp_name = components.to_h.select { |k, v| v.path_name == name }.first.last.name
72
+ comp = BrowserIO[comp_name]
73
+ options = comp.client_bio_opts
74
+ compiled_opts = Base64.encode64 options.to_json
75
+ js << Opal.compile("BrowserIO.components[:#{comp_name}].klass.instance_variable_set(:@bio_config, BrowserIO::Config.new(BrowserIO.components[:#{comp_name}].klass.bio_config.opts_dup.merge(JSON.parse(Base64.decode64('#{compiled_opts}')))))")
76
+ js
77
+ end
78
+ else
79
+ opts.loaded ||= {}
80
+
81
+ if !opts.loaded.keys.include? name
82
+ opts.loaded[name] = false
83
+
84
+ assets_url = options[:assets_url]
85
+
86
+ `$.getScript("/" + assets_url + "/" + name + ".js").done(function(){`
87
+ BrowserIO.opts.loaded[name] = true
88
+ method_called = options.delete(:method_called)
89
+ method_args = options.delete(:method_args)
90
+ name = options.delete(:name)
91
+ comp = BrowserIO[name, options]
92
+ requires = comp.bio_opts.requires
93
+
94
+ if requires.present? && requires.first.is_a?(Hash)
95
+ comps = []
96
+
97
+ ::Opal::Promise.when(*get_requires(requires, comps)).then do
98
+ comp.send(method_called, *method_args) if method_called
99
+ comp.bio_trigger :browser_events
100
+ end
101
+ else
102
+ comp.send(method_called, *method_args) if method_called
103
+ comp.bio_trigger :browser_events
104
+ end
105
+
106
+ promise.resolve true if promise
107
+ `}).fail(function(jqxhr, settings, exception){ window.console.log(exception); });`
108
+ end
109
+ end
110
+ end
111
+
112
+ def get_requires requires, reqs = [], from_get = false
113
+ promises = []
114
+
115
+ requires.each do |r|
116
+ if r[:requires].any?
117
+ promises << (promise = ::Opal::Promise.new)
118
+
119
+ a = []
120
+ c = []
121
+
122
+ get_requires(r[:requires], a, true)
123
+
124
+ a.each do |re|
125
+ c << -> do
126
+ p = ::Opal::Promise.new
127
+
128
+ path_name = re.delete(:path_name)
129
+ BrowserIO.javascript(path_name, re.reject { |k, v| k.to_s == 'requires'}, p)
130
+
131
+ p
132
+ end
133
+ end
134
+
135
+ ::Opal::Promise.when(*c.map!(&:call)).then do |*args|
136
+ path_name = r.delete(:path_name)
137
+ BrowserIO.javascript(path_name, r.reject { |k, v| k.to_s == 'requires'}, promise)
138
+ end
139
+ else
140
+ reqs << r
141
+
142
+ if !from_get
143
+ promises << (promise = ::Opal::Promise.new)
144
+
145
+ path_name = r.delete(:path_name)
146
+ BrowserIO.javascript(path_name, r.reject { |k, v| k.to_s == 'requires'}, promise)
147
+ end
148
+ end
149
+ end
150
+
151
+ promises
152
+ end
153
+
154
+ # Used to setup the component with default options.
155
+ #
156
+ # @example
157
+ # class SomeComponent < Component
158
+ # setup do |config|
159
+ # config.name :some
160
+ # end
161
+ # end
162
+ # @yield [Config]
163
+ def setup(&block)
164
+ javascript # This pre-compiles the core and store it in mem
165
+ block.call config
166
+ end
167
+
168
+ def config
169
+ @config ||= begin
170
+ args = { klass: self }
171
+
172
+ if RUBY_ENGINE == 'ruby'
173
+ args[:file_path] = caller.first.gsub(/(?<=\.rb):.*/, '')
174
+ end
175
+
176
+ Config.new(args)
177
+ end
178
+ end
179
+ alias_method :config, :config
180
+
181
+ def opts
182
+ config.opts
183
+ end
184
+ end
5
185
  end
@@ -0,0 +1,269 @@
1
+ module BrowserIO
2
+ class Component
3
+ include Methods
4
+
5
+ REJECTED_CLIENT_OPTS = %i(scope file_path methods_wrapped events klass on added_class_events)
6
+
7
+ class << self
8
+ alias_method :__new__, :new
9
+
10
+ # Override the default new behaviour
11
+ def new(*args, &block)
12
+ obj = allocate
13
+
14
+ obj.bio_opts.js = args.delete(:js)
15
+ obj.bio_opts.init = args.delete(:init)
16
+
17
+ # Merge other args into opts
18
+ args.each { |a| a.each {|k, v| obj.bio_opts[k] = v } } if client?
19
+
20
+ # Set all the requires
21
+ unless RUBY_ENGINE == 'opal'
22
+ obj.bio_opts.requires = obj.bio_config.get_requires
23
+ end
24
+
25
+ obj.bio_opts.events.scope = obj
26
+
27
+ # Set all the on events
28
+ obj.bio_opts.on.each do |*a, &b|
29
+ obj.bio_opts.events.add(*a.first.first, &a.first.last)
30
+ end
31
+ bio_opts.added_class_events = true
32
+
33
+ if obj.bio_opts.init && obj.method(:initialize).parameters.length > 0
34
+ obj.send :initialize, *obj.bio_opts.init, &block
35
+ else
36
+ obj.send :initialize, &block
37
+ end
38
+
39
+ unless bio_opts.methods_wrapped
40
+ obj.bio_opts.methods_wrapped = bio_opts.methods_wrapped = true
41
+
42
+ public_instance_methods(false).each do |meth|
43
+ alias_method :"bio_original_#{meth}", :"#{meth}"
44
+ define_method "#{meth}" do |*d_args|
45
+ if bio_opts.js
46
+ bio_opts.method_called = meth
47
+ bio_opts.method_args = *d_args
48
+ end
49
+
50
+ o_name = "bio_original_#{meth}"
51
+
52
+ if client? || method(o_name).parameters.length > 0
53
+ result = send(o_name, *d_args, &block)
54
+ else
55
+ result = send(o_name, &block)
56
+ end
57
+
58
+ # Append the initialize javscript
59
+ if server? && opts.js
60
+ result = result.to_html if result.is_a? DOM
61
+ result << bio_javascript
62
+ end
63
+
64
+ result
65
+ end
66
+ end
67
+ end
68
+
69
+ obj
70
+ end
71
+
72
+ # Used to setup the component with default options.
73
+ #
74
+ # @example
75
+ # class SomeComponent < Component
76
+ # setup do |config|
77
+ # config.name :some
78
+ # end
79
+ # end
80
+ # @yield [Config]
81
+ def bio_setup(&block)
82
+ block.call bio_config
83
+ end
84
+ alias_method :setup, :bio_setup
85
+
86
+ # Set templates
87
+ #
88
+ # @example
89
+ # tmpl :some_name, dom.find('#some-div')
90
+ # @return dom [DOM]
91
+ def bio_tmpl(name, dom = false, remove = false)
92
+ if dom
93
+ dom = remove ? dom.remove : dom
94
+ bio_opts.tmpl[name] = {
95
+ dom: dom,
96
+ html: dom.to_html
97
+ }
98
+ elsif t = bio_opts.tmpl[name]
99
+ dom = DOM.new t[:html]
100
+ else
101
+ false
102
+ end
103
+
104
+ dom
105
+ end
106
+ alias_method :tmpl, :bio_tmpl
107
+
108
+ def bio_dom
109
+ @bio_dom ||= DOM.new bio_opts.html
110
+ end
111
+ alias_method :dom, :bio_dom
112
+
113
+ # Shortcut for BrowserIO.components
114
+ #
115
+ # @return [Hash, BrowserIO.components]
116
+ def bio_components
117
+ BrowserIO.components ||= {}
118
+ end
119
+ alias_method :components, :bio_components
120
+
121
+ # Shortcut for the Config#opts
122
+ #
123
+ # @return [Openstruct, Config#opts]
124
+ def bio_opts
125
+ bio_config.opts
126
+ end
127
+ alias_method :opts, :bio_opts
128
+
129
+ def bio_config
130
+ @bio_config ||= begin
131
+ args = BrowserIO.config.opts_dup.merge(klass: self, object_events: {})
132
+
133
+ if RUBY_ENGINE == 'ruby'
134
+ args[:file_path] = caller.first.gsub(/(?<=\.rb):.*/, '')
135
+ args[:path_name] = args[:file_path]
136
+ .gsub(%r{(#{Dir.pwd}/|.*(?=browserio))}, '')
137
+ .gsub(/\.rb$/, '')
138
+ end
139
+
140
+ c = Config.new(args)
141
+
142
+ # If extending from a plugin it will automatically require it.
143
+ ancestors.each do |klass|
144
+ next if klass.to_s == name.to_s
145
+
146
+ if klass.method_defined?(:bio_opts) && klass.bio_opts.name.to_s =~ /_plugin$/
147
+ c.requires klass.bio_opts.name
148
+ end
149
+ end
150
+
151
+ c
152
+ end
153
+ end
154
+ alias_method :config, :bio_config
155
+
156
+ def on(*args, &block)
157
+ bio_opts.on << [args, block]
158
+ end
159
+
160
+ def method_missing(method, *args, &block)
161
+ if server? && bio_opts.scope.respond_to?(method, true)
162
+ bio_opts.scope.send method, *args, &block
163
+ else
164
+ super
165
+ end
166
+ end
167
+
168
+ def client_bio_opts
169
+ bio_config.opts_dup.reject {|k, v| REJECTED_CLIENT_OPTS.include? k }
170
+ end
171
+ end
172
+
173
+ # Duplicate of class condig [Config]
174
+ # @return config [Config]
175
+ def bio_config
176
+ @bio_config ||= begin
177
+ c = Config.new(self.class.bio_config.opts_dup.merge(events: Events.new))
178
+ c.opts.events.object_events = c.opts.object_events.dup
179
+ c.opts.object_events = {}
180
+ c
181
+ end
182
+ end
183
+ alias_method :config, :bio_config
184
+
185
+ # Duplicated of config.opts [Config#opts]
186
+ # @return opts [Config#opts]
187
+ def bio_opts
188
+ bio_config.opts
189
+ end
190
+ alias_method :opts, :bio_opts
191
+
192
+ # Grab a copy of the template
193
+ # @return dom [DOM]
194
+ def bio_tmpl(name)
195
+ self.class.bio_tmpl name
196
+ end
197
+ alias_method :tmpl, :bio_tmpl
198
+
199
+ # Dom
200
+ # @return bio_dom [Dom]
201
+ def bio_dom
202
+ @bio_dom ||= begin
203
+ if server?
204
+ DOM.new self.class.bio_dom.to_html
205
+ else
206
+ DOM.new(Element)
207
+ end
208
+ end
209
+ end
210
+ alias_method :dom, :bio_dom
211
+
212
+ # Special method that acts like the javascript equivalent
213
+ # @example
214
+ # foo = {
215
+ # bar: function { |moo|
216
+ # moo.call 'something'
217
+ # }
218
+ # }.to_n
219
+ def bio_function(*args, &block)
220
+ args.any? && raise(ArgumentError, '`function` does not accept arguments')
221
+ block || raise(ArgumentError, 'block required')
222
+ proc do |*a|
223
+ a.map! {|x| Native(`x`)}
224
+ @this = Native(`this`)
225
+ %x{
226
+ var bs = block.$$s,
227
+ result;
228
+ block.$$s = null;
229
+ result = block.apply(self, a);
230
+ block.$$s = bs;
231
+
232
+ return result;
233
+ }
234
+ end
235
+ end
236
+ alias_method :function, :bio_function
237
+
238
+ def bio_javascript
239
+ return unless server?
240
+
241
+ compiled_opts = Base64.encode64 client_bio_opts.to_json
242
+ name = bio_opts.file_path.gsub("#{Dir.pwd}/", '').gsub(/\.rb$/, '')
243
+
244
+ javascript = <<-JS
245
+ BrowserIO.javascript('#{name}', JSON.parse(Base64.decode64('#{compiled_opts}')))
246
+ JS
247
+ "<script>#{Opal.compile(javascript)}</script>"
248
+ end
249
+ alias_method :javscript, :bio_javascript
250
+
251
+ def client_bio_opts
252
+ bio_config.opts_dup.reject {|k, v| REJECTED_CLIENT_OPTS.include? k }
253
+ end
254
+ alias_method :client_opts, :client_bio_opts
255
+
256
+ def bio_trigger *args
257
+ bio_opts.events.trigger *args
258
+ end
259
+ alias_method :trigger, :bio_trigger
260
+
261
+ def method_missing(method, *args, &block)
262
+ if server? && bio_opts.scope.respond_to?(method, true)
263
+ bio_opts.scope.send method, *args, &block
264
+ else
265
+ super
266
+ end
267
+ end
268
+ end
269
+ end