wedge 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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