inesita-router 0.1.0

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: cfda9b707e3e98f034c012927370dc77b66ae0e9
4
+ data.tar.gz: 5ef031c92b95e87fca5babdfd84cc953f024d4c3
5
+ SHA512:
6
+ metadata.gz: a3eacee08c9678bcf32a683c11a6b278a78a5ca0a534825a204d635f646a8a8c3cf9cead165030411ae19490a9b2875f4794e11de14a9a995c861ac987768788
7
+ data.tar.gz: 7506170c651e8c1cc27fe4ef493ca7e314230c46730c9f9e8792ef2dc27a7d1965a19bb8fa9fe95fb2312ce979767e9f606fb1a5c383059ae187a5997e9d05bf
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/
2
+ *.gem
3
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache:
4
+ bundler: true
5
+ rvm:
6
+ - 2.3.1
7
+ before_install:
8
+ - "export PATH=$PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64/bin:$PATH"
9
+ - "if [ $(phantomjs --version) != '2.1.1' ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi"
10
+ - "if [ $(phantomjs --version) != '2.1.1' ]; then wget https://assets.membergetmember.co/software/phantomjs-2.1.1-linux-x86_64.tar.bz2 -O $PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2; fi"
11
+ - "if [ $(phantomjs --version) != '2.1.1' ]; then tar -xvf $PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs; fi"
12
+ - "phantomjs --version"
13
+ notifications:
14
+ webhooks:
15
+ urls: https://webhooks.gitter.im/e/04c689326f7cd8e4d499
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Michał Kalbarczyk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Inesita Router [![Gem Version](https://badge.fury.io/rb/inesita-router.svg)](http://badge.fury.io/rb/inesita-router) [![Code Climate](https://codeclimate.com/github/inesita-rb/inesita-router/badges/gpa.svg)](https://codeclimate.com/github/inesita-rb/inesita-router) [![Dependency Status](https://gemnasium.com/inesita-rb/inesita-router.svg)](https://gemnasium.com/inesita-rb/inesita-router) [![Build Status](https://travis-ci.org/inesita-rb/inesita-router.svg?branch=master)](https://travis-ci.org/inesita-rb/inesita-router)
2
+
3
+ Router for [Inesita](https://github.com/inesita-rb/inesita) framework.
4
+
5
+ ## Example
6
+
7
+ ```ruby
8
+ class Router
9
+ include Inesita::Router
10
+
11
+ def auth
12
+ unless store.logged_in?
13
+ go_to('/login')
14
+ end
15
+ end
16
+
17
+ def routes
18
+ route '/', to: Home, on_enter: method(:auth)
19
+ route '/list', to: List, on_enter: method(:auth)
20
+ route '/login', to: Login
21
+ end
22
+ end
23
+ ```
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require 'rspec/core/rake_task'
6
+ require 'opal/rspec/rake_task'
7
+
8
+ ENV['SPEC_OPTS'] = '--color'
9
+
10
+ Opal::RSpec::RakeTask.new(:spec_opal) do |_server, task|
11
+ task.pattern = 'spec/**/*_spec.rb'
12
+ task.default_path = 'spec/'
13
+ end
14
+
15
+ task default: [:spec_opal]
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'inesita-router'
3
+ s.version = '0.1.0'
4
+ s.authors = ['Michał Kalbarczyk']
5
+ s.email = 'fazibear@gmail.com'
6
+ s.homepage = 'http://github.com/inesita-rb/inesia-router'
7
+ s.summary = 'Router component for Inesita'
8
+ s.description = s.summary
9
+ s.license = 'MIT'
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
13
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ s.require_paths = ['lib']
15
+
16
+ s.add_dependency 'opal', '~> 0.10'
17
+ s.add_dependency 'inesita', '~> 0.6.0'
18
+
19
+ s.add_development_dependency 'bundler', '~> 1.0'
20
+ s.add_development_dependency 'rspec', '~> 3.0'
21
+ s.add_development_dependency 'opal-rspec', '~> 0.6.0'
22
+ s.add_development_dependency 'rake', '~> 11.0'
23
+ end
@@ -0,0 +1,4 @@
1
+ require 'opal'
2
+ require 'inesita'
3
+
4
+ Opal.append_path File.expand_path('../../opal', __FILE__)
@@ -0,0 +1,32 @@
1
+ module Inesita
2
+ module Browser
3
+ module_function
4
+
5
+ Location = Document.JS[:location]
6
+ History = Window.JS[:history]
7
+
8
+ def path
9
+ Location.JS[:pathname]
10
+ end
11
+
12
+ def query
13
+ Location.JS[:search]
14
+ end
15
+
16
+ def decode_uri_component(value)
17
+ JS.decodeURIComponent(value)
18
+ end
19
+
20
+ def push_state(path)
21
+ History.JS.pushState({}, nil, path)
22
+ end
23
+
24
+ def on_pop_state(&block)
25
+ Window.JS[:onpopstate] = block
26
+ end
27
+
28
+ def hash_change(&block)
29
+ AddEventListener.call(:hashchange, block)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,119 @@
1
+ module Inesita
2
+ module Router
3
+ include Inesita::Component
4
+
5
+ attr_reader :params
6
+
7
+ def initialize
8
+ @routes = Routes.new
9
+ raise Error, 'Add #routes method to router!' unless respond_to?(:routes)
10
+ routes
11
+ raise Error, 'Add #route to your #routes method!' if @routes.routes.empty?
12
+ find_route
13
+ parse_url_params
14
+ add_listeners
15
+ end
16
+
17
+ def self.included(base)
18
+ base.extend(Inesita::Component::ClassMethods)
19
+ Component.module_eval do
20
+ unless respond_to?(:__a)
21
+ alias_method :__a, :a
22
+ define_method(:a) do |params, &block|
23
+ params = { onclick: -> { router.go_to(params[:href]) } }.merge(params)
24
+ __a(params, &block)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def add_listeners
31
+ Browser.on_pop_state { find_route; parse_url_params; render! }
32
+ Browser.hash_change { find_route; parse_url_params; render! }
33
+ end
34
+
35
+ def route(*params, &block)
36
+ @routes.route(*params, &block)
37
+ end
38
+
39
+ def find_route
40
+ @routes.routes.each do |route|
41
+ next unless path.match(route[:regex])
42
+ return go_to(url_for(route[:redirect_to])) if route[:redirect_to]
43
+ return @route = route
44
+ end
45
+ raise Error, "Can't find route for url"
46
+ end
47
+
48
+ def find_component(route)
49
+ call_on_enter_callback(route)
50
+ @component_props = route[:component_props]
51
+ route[:component]
52
+ end
53
+
54
+ def render
55
+ component find_component(@route), props: @component_props if @route
56
+ end
57
+
58
+ def call_on_enter_callback(route)
59
+ return unless route[:on_enter]
60
+ if route[:on_enter].respond_to?(:call)
61
+ route[:on_enter].call
62
+ end
63
+ end
64
+
65
+ def go_to(path)
66
+ Browser.push_state(path)
67
+ find_route
68
+ parse_url_params
69
+ render!
70
+ false
71
+ end
72
+
73
+ def parse_url_params
74
+ @params = compotent_url_params
75
+ query[1..-1].split('&').each do |param|
76
+ key, value = param.split('=')
77
+ @params[Browser.decode_uri_component(key)] = Browser.decode_uri_component(value)
78
+ end unless query.empty?
79
+ end
80
+
81
+ def compotent_url_params
82
+ Hash[@route[:params].zip(path.match(@route[:regex])[1..-1])]
83
+ end
84
+
85
+ def url_for(name, params = nil)
86
+ route = @routes.routes.find do |r|
87
+ case name
88
+ when String
89
+ r[:name] == name || r[:path] == name
90
+ when Object
91
+ r[:component] == name
92
+ else
93
+ false
94
+ end
95
+ end
96
+ route ? url_with_params(route, params) : raise(Error, "Route '#{name}' not found.")
97
+ end
98
+
99
+ def query
100
+ Browser.query
101
+ end
102
+
103
+ def path
104
+ Browser.path
105
+ end
106
+
107
+ def current_url?(name)
108
+ path == url_for(name, params)
109
+ end
110
+
111
+ def url_with_params(route, params)
112
+ path = route[:path]
113
+ params.each do |key, value|
114
+ path = path.gsub(":#{key}", "#{value}")
115
+ end if params
116
+ path
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,79 @@
1
+ module Inesita
2
+ class Routes
3
+ attr_reader :routes
4
+
5
+ def initialize(parent = nil)
6
+ @parent = parent
7
+ @routes = []
8
+ end
9
+
10
+ def route(*params, &block)
11
+ path = params.first.gsub(/^\//, '')
12
+ path = @parent ? "#{@parent}/#{path}" : "/#{path}"
13
+
14
+ add_subroutes(path, &block) if block_given?
15
+
16
+ if params.last[:redirect_to]
17
+ add_redirect(path, params.last[:redirect_to])
18
+ else
19
+ add_route(params.last[:as], path, params.last[:to], params.last[:props], params.last[:on_enter])
20
+ end
21
+ end
22
+
23
+ def validate_component(component)
24
+ raise Error, 'Component not exists' unless component
25
+ raise Error, "Invalid #{component} class, should mixin Inesita::Component" unless component.include?(Inesita::Component)
26
+ end
27
+
28
+ def add_redirect(path, redirect_to)
29
+ @routes << {
30
+ path: path,
31
+ redirect_to: redirect_to
32
+ }.merge(build_params_and_regex(path))
33
+ end
34
+
35
+ def add_route(name, path, component, component_props, on_enter)
36
+ validate_component(component)
37
+ @routes << {
38
+ path: path,
39
+ component: component,
40
+ component_props: component_props,
41
+ on_enter: on_enter,
42
+ name: name || component.to_s.gsub(/(.)([A-Z])/, '\1_\2').downcase
43
+ }.merge(build_params_and_regex(path))
44
+ end
45
+
46
+ def add_subroutes(path, &block)
47
+ subroutes = Routes.new(path)
48
+ subroutes.instance_exec(&block)
49
+ @routes += subroutes.routes
50
+ end
51
+
52
+ def build_params_and_regex(path)
53
+ regex = ['^']
54
+ params = []
55
+ parts = path.split('/')
56
+ regex << '\/' if parts.empty?
57
+ parts.each do |part|
58
+ next if part.empty?
59
+ regex << '\/'
60
+ case part[0]
61
+ when ':'
62
+ params << part[1..-1]
63
+ regex << '([^\/]+)'
64
+ when '*'
65
+ params << part[1..-1]
66
+ regex << '(.*)'
67
+ break
68
+ else
69
+ regex << part
70
+ end
71
+ end
72
+ regex << '$'
73
+ {
74
+ regex: Regexp.new(regex.join),
75
+ params: params
76
+ }
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,3 @@
1
+ require 'inesita-router/browser'
2
+ require 'inesita-router/routes'
3
+ require 'inesita-router/router'
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe Inesita::Router do
4
+ let(:element) { Inesita::Browser::Document.JS.createElement('div') }
5
+ let(:wrong_router) { Class.new { include Inesita::Router } }
6
+ let(:empty_router) { Class.new { include Inesita::Router; def routes; end } }
7
+ let(:router) do
8
+ Class.new do
9
+ include Inesita::Router
10
+
11
+ class TestComponent
12
+ include Inesita::Component
13
+
14
+ def render
15
+ div { "test" }
16
+ end
17
+ end
18
+
19
+ class OtherTestComponent
20
+ include Inesita::Component
21
+
22
+ def render
23
+ div { "other" }
24
+ end
25
+ end
26
+
27
+ def routes
28
+ route '/', to: TestComponent
29
+ route '/other', to: OtherTestComponent
30
+ end
31
+ end
32
+ end
33
+
34
+ it 'should fail without routes' do
35
+ expect { wrong_router.new.mount_to(element) }.to raise_error Inesita::Error
36
+ end
37
+
38
+ it 'should fail with empty routes' do
39
+ expect { empty_router.new }.to raise_error Inesita::Error
40
+ end
41
+
42
+ it 'should not fail with routes' do
43
+ expect { router.new }.not_to raise_error
44
+ end
45
+
46
+ describe '#url_for' do
47
+ it 'should return url for component name' do
48
+ expect(router.new.url_for(:test_component)).to eq '/'
49
+ end
50
+
51
+ it 'should return url for component name' do
52
+ expect(router.new.url_for(:other_test_component)).to eq '/other'
53
+ end
54
+
55
+ it 'should fail when no route for component' do
56
+ expect { router.new.url_for(:nothing) }.to raise_error Inesita::Error
57
+ end
58
+ end
59
+
60
+ describe '#current_url?' do
61
+ it 'should return true for current url' do
62
+ expect(router.mount_to(element).current_url?(:test_component)).to eq true
63
+ end
64
+
65
+ it 'should return false for current url' do
66
+ expect(router.mount_to(element).current_url?(:other_test_component)).to eq false
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,4 @@
1
+ include RSpec
2
+
3
+ require 'inesita'
4
+ require 'inesita-router'
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: inesita-router
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Michał Kalbarczyk
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: opal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.10'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: inesita
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.6.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: opal-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.6.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.6.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '11.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '11.0'
97
+ description: Router component for Inesita
98
+ email: fazibear@gmail.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - ".gitignore"
104
+ - ".travis.yml"
105
+ - Gemfile
106
+ - LICENSE.md
107
+ - README.md
108
+ - Rakefile
109
+ - inesita-router.gemspec
110
+ - lib/inesita-router.rb
111
+ - opal/inesita-router.rb
112
+ - opal/inesita-router/browser.rb
113
+ - opal/inesita-router/router.rb
114
+ - opal/inesita-router/routes.rb
115
+ - spec/router_spec.rb
116
+ - spec/spec_helper.rb
117
+ homepage: http://github.com/inesita-rb/inesia-router
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.5.1
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Router component for Inesita
141
+ test_files:
142
+ - spec/router_spec.rb
143
+ - spec/spec_helper.rb