wedge 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8340fb116771d36a3d38e5b7962ea7997dc7395c
4
+ data.tar.gz: 2a825be528f91994b5b2d5940c97da26e8324c54
5
+ SHA512:
6
+ metadata.gz: 9d92de2a07944a6114c5cc5753c3410d52b9d6e7e72a5ad9258d626aef3ebe571b5e0c859aefb88e7c49a36e4faf7375c78ed1a127edc1c3a8201da0b1a4ff6d
7
+ data.tar.gz: 96c2984a99b0b44f923da8dfbc719805ffa789e2dfb96307d27e77835b2d66aef1929cdae8c6eedd1e2128c94abae9100a02899e8398d9111a349f8e30053116
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in BrowserIO.gemspec
4
+ gemspec
5
+
6
+ gem 'opal', github: 'opal/opal'
7
+ gem 'opal-jquery', github: 'opal/opal-jquery'
8
+ gem 'thin'
9
+ gem 'roda-bin'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 cj
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # BrowserIO
2
+
3
+ Components for Ruby.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'browserio'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install browserio
20
+
21
+ ## Basic Usage
22
+
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'
42
+
43
+ ## Contributing
44
+
45
+ 1. Fork it ( https://github.com/[my-github-username]/BrowserIO/fork )
46
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
47
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
48
+ 4. Push to the branch (`git push origin my-new-feature`)
49
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
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
@@ -0,0 +1,93 @@
1
+ class Roda
2
+ module RodaPlugins
3
+ module Wedge
4
+ def self.configure(app, opts = {})
5
+ if app.opts[:wedge]
6
+ app.opts[:wedge].merge!(opts)
7
+ else
8
+ app.opts[:wedge] = opts.dup
9
+ end
10
+
11
+ opts = app.opts[:wedge]
12
+
13
+ opts.each do |k, v|
14
+ case k.to_s
15
+ when 'plugins'
16
+ v.each { |p| ::Wedge.config.plugin p }
17
+ when 'scope'
18
+ begin
19
+ ::Wedge.config.scope v.new
20
+ rescue
21
+ ::Wedge.config.scope v.new('')
22
+ end
23
+ else
24
+ ::Wedge.config.send(k, v)
25
+ end
26
+ end
27
+ end
28
+
29
+ module InstanceMethods
30
+ def wedge(*args)
31
+ args << { scope: self }
32
+ ::Wedge[*args]
33
+ end
34
+ end
35
+
36
+ module RequestClassMethods
37
+ def wedge_route_regex
38
+ assets_url = ::Wedge.assets_url.gsub(%r{^(http://[^\/]*\/|\/)}, '')
39
+ %r{#{assets_url}/(.*)\.(.*)$}
40
+ end
41
+ end
42
+
43
+ module RequestMethods
44
+ def wedge_assets
45
+ on self.class.wedge_route_regex do |component, ext|
46
+ case ext
47
+ when 'map'
48
+ ::Wedge.source_map component
49
+ when 'rb'
50
+ if component =~ /^wedge/
51
+ path = ::Wedge.opts.file_path.gsub(/\/wedge.rb$/, '')
52
+ File.read("#{path}/#{component}.rb")
53
+ else
54
+ File.read("#{ROOT_PATH}/#{component}.rb")
55
+ end
56
+ when 'call'
57
+ body = scope.request.body.read
58
+ data = scope.request.params
59
+
60
+ begin
61
+ data.merge!(body ? JSON.parse(body) : {})
62
+ rescue
63
+ # can't be parsed by json
64
+ end
65
+
66
+ data = data.indifferent
67
+ name = data.delete(:name)
68
+ method_called = data.delete(:method_called)
69
+ method_args = data.delete(:method_args)
70
+
71
+ res = scope.wedge(name, data).send(method_called, *method_args) || ''
72
+
73
+ scope.response.headers["BIO-CSRF-TOKEN"] = scope.csrf_token if scope.methods.include? :csrf_token
74
+
75
+ if res.is_a? Hash
76
+ scope.response.headers["Content-Type"] = 'application/json; charset=UTF-8'
77
+ res = res.to_json
78
+ else
79
+ res = res.to_s
80
+ end
81
+
82
+ res
83
+ else
84
+ "#{::Wedge.javascript(component)}\n//# sourceMappingURL=/assets/wedge/#{component}.map"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ register_plugin(:wedge, Wedge)
92
+ end
93
+ end
data/lib/wedge.rb ADDED
@@ -0,0 +1,238 @@
1
+ require 'wedge/opal'
2
+ require 'wedge/version'
3
+ require 'wedge/utilis/indifferent_hash'
4
+ require 'wedge/utilis/hash'
5
+ require 'wedge/utilis/blank'
6
+ require 'wedge/utilis/methods'
7
+ require 'wedge/utilis/try'
8
+ require 'wedge/utilis/titleize'
9
+ require 'wedge/utilis/element'
10
+ require 'base64'
11
+ unless RUBY_ENGINE == 'opal'
12
+ require 'nokogiri'
13
+ require 'wedge/utilis/nokogiri'
14
+ end
15
+ require 'wedge/html'
16
+ require 'wedge/dom'
17
+ require 'wedge/config'
18
+ require 'wedge/component'
19
+
20
+ module Wedge
21
+ include Methods
22
+
23
+ class << self
24
+ attr_accessor :requires, :loaded_requires, :loaded_requires_events, :javascript_cache,
25
+ :wedge_javascript_loaded
26
+
27
+ def cache
28
+ javascript
29
+ end
30
+
31
+ def assets_url
32
+ "#{opts.assets_url}#{opts.cache_assets ? "/#{opts.assets_key}" : ''}"
33
+ end
34
+
35
+ def script_tag
36
+ "<script src='#{assets_url}/wedge.js'></script>"
37
+ end
38
+
39
+ # Used to call a component.
40
+ #
41
+ # @example
42
+ # Browser[:foo].bar
43
+ #
44
+ # @param name [String, Symbol, #to_s] The unique name given to a component.
45
+ # @return [Wedge::Component#method] Last line of the method called.
46
+ def [](name, *args)
47
+ component = components[name.to_sym]
48
+
49
+ component.klass.new(*args)
50
+ end
51
+
52
+ def components
53
+ @components ||= OpenStruct.new
54
+ end
55
+
56
+ unless RUBY_ENGINE == 'opal'
57
+ # Returns the build object for opal.
58
+ #
59
+ # @param path [String] require path to file to build.
60
+ # @return [String, Opal::Builder#build]
61
+ def build(path = 'wedge', options = {})
62
+ append_paths
63
+ Opal::Builder.build(path, options)
64
+ end
65
+
66
+ # Source maps for the javascript
67
+ def source_map(path = 'wedge', options = {})
68
+ build(path, options).source_map
69
+ end
70
+
71
+ # Append the correct paths to opal.
72
+ #
73
+ # @return [Array] List of opal paths.
74
+ def append_paths
75
+ @append_paths ||= begin
76
+ file = method(:components).source_location.first.sub('/wedge.rb', '')
77
+ Wedge::Opal.append_path file
78
+ Wedge::Opal.append_path Dir.pwd
79
+ end
80
+ end
81
+ end
82
+
83
+ # Return the opal javascript.
84
+ def javascript(path_name = 'wedge', options = {}, promise = false)
85
+ if server?
86
+ if path_name == 'wedge'
87
+ @wedge_javascript ||= begin
88
+ @wedge_javascript_loaded = true
89
+ requires = {}
90
+
91
+ @javascript_cache ||= {}
92
+
93
+ components.to_h.each do |k, v|
94
+ requires[k] = v.klass.wedge_config.get_requires
95
+ javascript(v.klass.wedge_opts[:path_name])
96
+ end
97
+
98
+ compiled_requires = Base64.encode64 requires.to_json
99
+ assets_key = opts.assets_key
100
+ cache_assets = opts.cache_assets
101
+
102
+ js = build(path_name, options).javascript
103
+ js << Opal.compile("Wedge.instance_variable_set(:@requires, JSON.parse(Base64.decode64('#{compiled_requires}')))")
104
+ # fix: we need to just merge in all config opts and just reject
105
+ # certain ones
106
+ js << Opal.compile("Wedge.config.assets_key('#{assets_key}')") if assets_key
107
+ js << Opal.compile("Wedge.config.cache_assets('#{cache_assets}')") if cache_assets
108
+ ##############################################################
109
+ js
110
+ end
111
+ else
112
+ @javascript_cache[path_name] ||= begin
113
+ js = build(path_name, options).javascript
114
+ comp_name = components.to_h.select { |k, v| v.path_name == path_name }.first.last.name
115
+ comp = Wedge[comp_name]
116
+ options = comp.client_wedge_opts
117
+ compiled_opts = Base64.encode64 options.to_json
118
+ js << Opal.compile("Wedge.components[:#{comp_name}].klass.instance_variable_set(:@wedge_config, Wedge::Config.new(Wedge.components[:#{comp_name}].klass.wedge_config.opts_dup.merge(JSON.parse(Base64.decode64('#{compiled_opts}')))))")
119
+ end
120
+ end
121
+ else
122
+ Wedge.loaded_requires ||= []
123
+ Wedge.loaded_requires_events ||= []
124
+ reqs = Wedge.requires[options[:name].to_sym].dup
125
+ promise = Promise.new
126
+ requires = get_requires(reqs)
127
+
128
+ load_requires(requires.dup, promise)
129
+
130
+ promise.then do
131
+ load_comp(options).then do
132
+ method_called = options[:method_called]
133
+ method_args = options[:method_args]
134
+ name = options[:name]
135
+ comp = Wedge[name, options]
136
+
137
+ Document.ready? do
138
+ trigger_requires_events requires.dup
139
+ comp.send(method_called, *method_args) if method_called
140
+ comp.wedge_trigger :browser_events
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ def trigger_requires_events requires
148
+ reqs = requires.shift
149
+
150
+ reqs.each do |r|
151
+ next if Wedge.loaded_requires_events.include? r[:name]
152
+ Wedge.loaded_requires_events << r[:name]
153
+ comp = Wedge[r[:name], r]
154
+ comp.wedge_trigger :browser_events
155
+ end
156
+
157
+ trigger_requires_events requires if requires.any?
158
+ end
159
+
160
+ def load_requires requires, promise = Promise.new
161
+ reqs = requires.shift
162
+ promises = []
163
+
164
+ reqs.each do |r|
165
+ next if Wedge.loaded_requires.include? r[:name]
166
+
167
+ Wedge.loaded_requires << r[:name]
168
+
169
+ promises << -> { load_comp r }
170
+ end
171
+
172
+ Promise.when(*promises.map!(&:call)).then do
173
+ requires.any?? load_requires(requires, promise) : promise.resolve(true)
174
+ end
175
+ end
176
+
177
+ def get_requires reqs, requires_array = []
178
+ new_reqs = []
179
+
180
+ reqs.each do |r|
181
+ if r[:requires].any?
182
+ get_requires(r[:requires], requires_array)
183
+ end
184
+
185
+ new_reqs << r
186
+ end
187
+
188
+ requires_array << new_reqs if new_reqs.any?
189
+
190
+ requires_array
191
+ end
192
+
193
+ def load_comp options = {}, promise = Promise.new
194
+ path_name = options[:path_name]
195
+ assets_url = Wedge.assets_url
196
+
197
+ # fix: this could give people unwanted behaviour, change getScript to just
198
+ # use ajax.
199
+ `jQuery.ajaxSetup({ cache: true })` if Wedge.opts.cache_assets
200
+ `$.getScript(assets_url + "/" + path_name + ".js").done(function(){`
201
+ promise.resolve true
202
+ `}).fail(function(jqxhr, settings, exception){ window.console.log(exception); });`
203
+ #########################################################################
204
+
205
+ promise
206
+ end
207
+
208
+ # Used to setup the component with default options.
209
+ #
210
+ # @example
211
+ # class SomeComponent < Component
212
+ # setup do |config|
213
+ # config.name :some
214
+ # end
215
+ # end
216
+ # @yield [Config]
217
+ def setup(&block)
218
+ block.call config if block_given?
219
+ end
220
+
221
+ def config
222
+ @config ||= begin
223
+ args = { klass: self }
224
+
225
+ unless RUBY_ENGINE == 'opal'
226
+ args[:file_path] = caller.first.gsub(/(?<=\.rb):.*/, '')
227
+ args[:assets_key] = ENV.fetch('SOURCE_VERSION') { `git rev-parse HEAD 2>/dev/null`.to_s.strip }
228
+ end
229
+
230
+ Config.new(args)
231
+ end
232
+ end
233
+
234
+ def opts
235
+ config.opts
236
+ end
237
+ end
238
+ end