browserio 0.0.1 → 0.0.2

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