menilite 0.5.4 → 0.5.5
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 +4 -4
- data/docs/articles/getting-started.md +85 -0
- data/docs/articles/list.yaml +1 -0
- data/docs/articles/model.md +40 -0
- data/docs/css/milligram.min.css +11 -0
- data/docs/css/style.css +62 -0
- data/docs/index.html +113 -0
- data/docs/src/build.rb +21 -0
- data/docs/views/index.haml +22 -0
- data/lib/menilite/client/http.rb +17 -30
- data/lib/menilite/client/store.rb +29 -4
- data/lib/menilite/model.rb +11 -1
- data/lib/menilite/server/activerecord_store.rb +9 -1
- data/lib/menilite/server/router.rb +12 -0
- data/lib/menilite/server/serializer.rb +1 -1
- data/lib/menilite/version.rb +1 -1
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c317e28a8910d938484dbea1431a8ebac0e66a094641e6e80506f41dc5e18054
|
4
|
+
data.tar.gz: 5344962b1388ffbcba13d4edd3ada16037b18c6387d15493ad3ba2ef8eb59109
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df8013186d7e01816cb655e5d72773cc3b0de44a9cca2cd33dfe38f1fea45466cc8e201e763b997d8770243c5c55cdd27665a96d19d9d4df7a88c821a0a3b01f
|
7
|
+
data.tar.gz: c411bcd675aaabf4a4b86501a943cb18adf5c764cecff1075f9bcfe4bc14cb5ec28efbddcf0b9444d2651e9a14cfe2e79a504836c496cdc944e8079b6b64c1e6
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Getting started
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'menilite'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install menilite
|
18
|
+
|
19
|
+
## How to use
|
20
|
+
|
21
|
+
You can generate the template project by [Silica](https://github.com/youchan/silica) to get started.
|
22
|
+
|
23
|
+
$ gem install silica
|
24
|
+
$ silica new your-app
|
25
|
+
$ cd your-app
|
26
|
+
$ bundle install
|
27
|
+
$ bundle exec rackup
|
28
|
+
|
29
|
+
## Model definition
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
class User < Menilite::Model
|
33
|
+
field :name
|
34
|
+
field :password
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
Model definition is shared from the client side (compiled by Opal) and the server side (in MRI).
|
39
|
+
In this tiny example, `User` model has two string fields (`name` and `password`).
|
40
|
+
Field has a type and the type is set `string` as default.
|
41
|
+
You can specify another type by the following way, for example.
|
42
|
+
|
43
|
+
field :active, :boolean
|
44
|
+
|
45
|
+
## Action
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class User < Menilite::Model
|
49
|
+
action :signup, save: true do |password|
|
50
|
+
self.password = BCrypt::Password.create(password)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
Models can have actions. The action is executed on the server side and the client code call the action as a method.
|
56
|
+
|
57
|
+
on the client side
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
user = User.new(name: 'youchan')
|
61
|
+
user.auth('topsecret')
|
62
|
+
```
|
63
|
+
|
64
|
+
## Controller
|
65
|
+
|
66
|
+
Controllers can have actions too.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class ApplicationController < Menilite::Controller
|
70
|
+
action :login do |username, password|
|
71
|
+
user = User.find(name: username)
|
72
|
+
if user && user.auth(password)
|
73
|
+
session[:user_id] = user.id
|
74
|
+
else
|
75
|
+
raise 'login failed'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
The action of Controller is defined as a class method on the client side.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
ApplicationController.login('youchan', 'topsecret')
|
85
|
+
```
|
@@ -0,0 +1 @@
|
|
1
|
+
- getting-started.md
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Model
|
2
|
+
|
3
|
+
## How to make a model
|
4
|
+
|
5
|
+
### 1st step: Create a database migration
|
6
|
+
|
7
|
+
Create a database migration script of `ActiveRecord` to make a table for model.
|
8
|
+
|
9
|
+
```terminal
|
10
|
+
$ bundle exec rake db:create_migration create_user
|
11
|
+
```
|
12
|
+
|
13
|
+
Edit the migration file.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
|
17
|
+
```
|
18
|
+
|
19
|
+
|
20
|
+
### User privilege
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
class UserPrivilege < Menilite::Privilege
|
24
|
+
def key
|
25
|
+
:user_privilege
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(user)
|
29
|
+
@user = user
|
30
|
+
end
|
31
|
+
|
32
|
+
def filter
|
33
|
+
{ user_id: @user.id }
|
34
|
+
end
|
35
|
+
|
36
|
+
def fields
|
37
|
+
{ user_id: @user.id }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/*!
|
2
|
+
* Milligram v1.3.0
|
3
|
+
* https://milligram.github.io
|
4
|
+
*
|
5
|
+
* Copyright (c) 2017 CJ Patoilo
|
6
|
+
* Licensed under the MIT license
|
7
|
+
*/
|
8
|
+
|
9
|
+
*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#606c76;font-family:'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:0.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#9b4dca;border:0.1rem solid #9b4dca;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3.0rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type='button']:focus,input[type='button']:hover,input[type='reset']:focus,input[type='reset']:hover,input[type='submit']:focus,input[type='submit']:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type='button'][disabled],input[type='reset'][disabled],input[type='submit'][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:#9b4dca;border-color:#9b4dca}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{background-color:transparent;color:#9b4dca}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type='button'].button-outline:focus,input[type='button'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='submit'].button-outline:focus,input[type='submit'].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{border-color:inherit;color:#9b4dca}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{background-color:transparent;border-color:transparent;color:#9b4dca}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type='button'].button-clear:focus,input[type='button'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='submit'].button-clear:focus,input[type='submit'].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:#9b4dca}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:0.3rem solid #9b4dca;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:0.1rem solid #f4f5f6;margin:3.0rem 0}input[type='email'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1.0rem;width:100%}input[type='email']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,textarea:focus,select:focus{border-color:#9b4dca;outline:0}select{background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 0 29 14" width="29"><path fill="#d1d1d1" d="M9.37727 3.625l5.08154 6.93523L19.54036 3.625"/></svg>') center right no-repeat;padding-right:3.0rem}select:focus{background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 0 29 14" width="29"><path fill="#9b4dca" d="M9.37727 3.625l5.08154 6.93523L19.54036 3.625"/></svg>')}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{display:inline-block;font-weight:normal;margin-left:.5rem}.container{margin:0 auto;max-width:112.0rem;padding:0 2.0rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{-ms-grid-row-align:center;align-self:center}@media (min-width: 40rem){.row{flex-direction:row;margin-left:-1.0rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1.0rem}}a{color:#9b4dca;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3.0rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1.0rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;width:100%}td,th{border-bottom:0.1rem solid #e1e1e1;padding:1.2rem 1.5rem;text-align:left}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}b,strong{font-weight:bold}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2.0rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right}
|
10
|
+
|
11
|
+
/*# sourceMappingURL=milligram.min.css.map */
|
data/docs/css/style.css
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
body {
|
2
|
+
margin: 0;
|
3
|
+
background-color: #eeeeee;
|
4
|
+
}
|
5
|
+
|
6
|
+
.header {
|
7
|
+
height: 52px;
|
8
|
+
background-color: #f0f0ff;
|
9
|
+
border-bottom: solid 1px #aaaaaa;
|
10
|
+
}
|
11
|
+
|
12
|
+
.header .header-content {
|
13
|
+
height: 100%;
|
14
|
+
margin: 0 auto;
|
15
|
+
width: 1024px;
|
16
|
+
}
|
17
|
+
|
18
|
+
svg.github-corner {
|
19
|
+
width: 52px;
|
20
|
+
height: 52px;
|
21
|
+
}
|
22
|
+
|
23
|
+
p.title {
|
24
|
+
height: 100%;
|
25
|
+
margin: 0;
|
26
|
+
padding-top: 8px;
|
27
|
+
font-size: 160%;
|
28
|
+
font-weight: 200;
|
29
|
+
}
|
30
|
+
|
31
|
+
.wrap-main {
|
32
|
+
margin: 0 auto;
|
33
|
+
width: 1024px;
|
34
|
+
background-color: #ffffff;
|
35
|
+
}
|
36
|
+
|
37
|
+
.wrap-2column {
|
38
|
+
display: flex;
|
39
|
+
height: calc(100vh - 52px);
|
40
|
+
}
|
41
|
+
|
42
|
+
.nav {
|
43
|
+
flex: 20%;
|
44
|
+
border-right: solid 1px #aaaaaa;
|
45
|
+
}
|
46
|
+
|
47
|
+
.nav ul {
|
48
|
+
list-style: none;
|
49
|
+
margin: 0;
|
50
|
+
}
|
51
|
+
|
52
|
+
.nav li {
|
53
|
+
border-bottom: solid 1px #aaaaaa;
|
54
|
+
padding: 1rem;
|
55
|
+
}
|
56
|
+
|
57
|
+
.content {
|
58
|
+
flex: 80%;
|
59
|
+
padding: 10px;
|
60
|
+
height: 100%;
|
61
|
+
overflow: scroll;
|
62
|
+
}
|
data/docs/index.html
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset='utf-8'>
|
5
|
+
<link href='css/milligram.min.css' rel='stylesheet'>
|
6
|
+
<link href='css/style.css' rel='stylesheet'>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<div class='header'>
|
10
|
+
<div class='header-content'>
|
11
|
+
<p class='title'>menilite documentation</p>
|
12
|
+
</div>
|
13
|
+
<div class='corner-icon'>
|
14
|
+
<a href="https://github.com/youchan/menilite" class="github-corner" aria-label="View source on GitHub"><svg width="52" height="52" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
<div class='wrap-main'>
|
18
|
+
<div class='wrap-2column'>
|
19
|
+
<div class='nav'>
|
20
|
+
<ul>
|
21
|
+
<li>Getting started</li>
|
22
|
+
</ul>
|
23
|
+
</div>
|
24
|
+
<div class='content'>
|
25
|
+
<div class='ch'><h1>Getting started</h1>
|
26
|
+
|
27
|
+
<h2>Installation</h2>
|
28
|
+
|
29
|
+
<p>Add this line to your application's Gemfile:</p>
|
30
|
+
|
31
|
+
<pre><code class="ruby">gem 'menilite'
|
32
|
+
</code></pre>
|
33
|
+
|
34
|
+
<p>And then execute:</p>
|
35
|
+
|
36
|
+
<pre><code>$ bundle
|
37
|
+
</code></pre>
|
38
|
+
|
39
|
+
<p>Or install it yourself as:</p>
|
40
|
+
|
41
|
+
<pre><code>$ gem install menilite
|
42
|
+
</code></pre>
|
43
|
+
|
44
|
+
<h2>How to use</h2>
|
45
|
+
|
46
|
+
<p>You can generate the template project by <a href="https://github.com/youchan/silica">Silica</a> to get started.</p>
|
47
|
+
|
48
|
+
<pre><code>$ gem install silica
|
49
|
+
$ silica new your-app
|
50
|
+
$ cd your-app
|
51
|
+
$ bundle install
|
52
|
+
$ bundle exec rackup
|
53
|
+
</code></pre>
|
54
|
+
|
55
|
+
<h2>Model definition</h2>
|
56
|
+
|
57
|
+
<pre><code class="ruby">class User < Menilite::Model
|
58
|
+
field :name
|
59
|
+
field :password
|
60
|
+
end
|
61
|
+
</code></pre>
|
62
|
+
|
63
|
+
<p>Model definition is shared from the client side (compiled by Opal) and the server side (in MRI).<br>
|
64
|
+
In this tiny example, <code>User</code> model has two string fields (<code>name</code> and <code>password</code>).<br>
|
65
|
+
Field has a type and the type is set <code>string</code> as default.<br>
|
66
|
+
You can specify another type by the following way, for example.</p>
|
67
|
+
|
68
|
+
<pre><code>field :active, :boolean
|
69
|
+
</code></pre>
|
70
|
+
|
71
|
+
<h2>Action</h2>
|
72
|
+
|
73
|
+
<pre><code class="ruby">class User < Menilite::Model
|
74
|
+
action :signup, save: true do |password|
|
75
|
+
self.password = BCrypt::Password.create(password)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
</code></pre>
|
79
|
+
|
80
|
+
<p>Models can have actions. The action is executed on the server side and the client code call the action as a method.</p>
|
81
|
+
|
82
|
+
<p>on the client side</p>
|
83
|
+
|
84
|
+
<pre><code class="ruby">user = User.new(name: 'youchan')
|
85
|
+
user.auth('topsecret')
|
86
|
+
</code></pre>
|
87
|
+
|
88
|
+
<h2>Controller</h2>
|
89
|
+
|
90
|
+
<p>Controllers can have actions too.</p>
|
91
|
+
|
92
|
+
<pre><code class="ruby">class ApplicationController < Menilite::Controller
|
93
|
+
action :login do |username, password|
|
94
|
+
user = User.find(name: username)
|
95
|
+
if user && user.auth(password)
|
96
|
+
session[:user_id] = user.id
|
97
|
+
else
|
98
|
+
raise 'login failed'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
</code></pre>
|
103
|
+
|
104
|
+
<p>The action of Controller is defined as a class method on the client side.</p>
|
105
|
+
|
106
|
+
<pre><code class="ruby">ApplicationController.login('youchan', 'topsecret')
|
107
|
+
</code></pre>
|
108
|
+
</div>
|
109
|
+
</div>
|
110
|
+
</div>
|
111
|
+
</div>
|
112
|
+
</body>
|
113
|
+
</html>
|
data/docs/src/build.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "haml"
|
2
|
+
require "psych"
|
3
|
+
require "redcarpet"
|
4
|
+
|
5
|
+
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML,
|
6
|
+
autolink: true,
|
7
|
+
tables: true,
|
8
|
+
fenced_code_blocks: true)
|
9
|
+
|
10
|
+
haml = File.read(File.expand_path("../views/index.haml", __dir__))
|
11
|
+
list = Psych.load_file(File.expand_path("../articles/list.yaml", __dir__))
|
12
|
+
|
13
|
+
titles, contents = list.each_with_object([[], []]) do |name, (titles, contents)|
|
14
|
+
md = File.read(File.expand_path("../articles/#{name}", __dir__))
|
15
|
+
titles << md.split("\n").first.sub(/^\# (.*)/, '\\1')
|
16
|
+
contents << markdown.render(md)
|
17
|
+
end
|
18
|
+
|
19
|
+
File.open(File.expand_path("../index.html", __dir__), "w") do |out|
|
20
|
+
out << Haml::Engine.new(haml, :format => :html5).render(Object.new, {titles: titles, contents: contents})
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%meta{charset: "utf-8"}
|
5
|
+
%link{rel:"stylesheet", href: "css/milligram.min.css"}
|
6
|
+
%link{rel:"stylesheet", href: "css/style.css"}
|
7
|
+
%body
|
8
|
+
.header
|
9
|
+
.header-content
|
10
|
+
%p.title menilite documentation
|
11
|
+
.corner-icon
|
12
|
+
!= '<a href="https://github.com/youchan/menilite" class="github-corner" aria-label="View source on GitHub"><svg width="52" height="52" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>'
|
13
|
+
.wrap-main
|
14
|
+
.wrap-2column
|
15
|
+
.nav
|
16
|
+
%ul
|
17
|
+
- titles.each do |title|
|
18
|
+
%li= title
|
19
|
+
.content
|
20
|
+
- contents.each do |content|
|
21
|
+
.ch!= content
|
22
|
+
|
data/lib/menilite/client/http.rb
CHANGED
@@ -2,45 +2,32 @@ module Menilite
|
|
2
2
|
module Http
|
3
3
|
class << self
|
4
4
|
def get_json(url, &block)
|
5
|
-
(
|
6
|
-
|
7
|
-
%x(
|
8
|
-
fetch(
|
9
|
-
url,
|
10
|
-
{
|
11
|
-
method: 'get',
|
12
|
-
headers: {
|
13
|
-
'Accept': 'application/json',
|
14
|
-
'Content-Type': 'application/json'
|
15
|
-
},
|
16
|
-
credentials: "same-origin",
|
17
|
-
}
|
18
|
-
).then(callback);
|
19
|
-
)
|
20
|
-
|
21
|
-
promise
|
5
|
+
request_json(url, :get, &block)
|
22
6
|
end
|
23
7
|
|
24
8
|
def post_json(url, data, &block)
|
9
|
+
request_json(url, :post, data, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def request_json(url, method, data=nil, &block)
|
25
13
|
(callback, promise) = prepare(url, &block)
|
26
14
|
|
15
|
+
params = {
|
16
|
+
method: method,
|
17
|
+
headers: {
|
18
|
+
'Accept': 'application/json',
|
19
|
+
'Content-Type': 'application/json'
|
20
|
+
},
|
21
|
+
credentials: "same-origin"
|
22
|
+
}
|
23
|
+
|
24
|
+
params[:body] = data.to_json if data
|
25
|
+
|
27
26
|
%x(
|
28
|
-
fetch(
|
29
|
-
url,
|
30
|
-
{
|
31
|
-
method: 'post',
|
32
|
-
headers: {
|
33
|
-
'Accept': 'application/json',
|
34
|
-
'Content-Type': 'application/json'
|
35
|
-
},
|
36
|
-
credentials: "same-origin",
|
37
|
-
body: #{data.to_json}
|
38
|
-
}
|
39
|
-
).then(callback);
|
27
|
+
fetch(url, params.$to_n()).then(callback);
|
40
28
|
)
|
41
29
|
|
42
30
|
promise
|
43
|
-
|
44
31
|
end
|
45
32
|
|
46
33
|
private
|
@@ -20,6 +20,14 @@ module Menilite
|
|
20
20
|
self[model_class][id]
|
21
21
|
end
|
22
22
|
|
23
|
+
def fetch(model_class, filter:)
|
24
|
+
@tables[model_class].find{|x| match_filter?(x, filter) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def match_filter?(model, filter)
|
28
|
+
filter.all? {|k, v| model[k] == v }
|
29
|
+
end
|
30
|
+
|
23
31
|
def save(model)
|
24
32
|
is_array = model.is_a?(Array)
|
25
33
|
models = is_array ? model : [ model ]
|
@@ -48,9 +56,11 @@ module Menilite
|
|
48
56
|
|
49
57
|
def fetch!(model_class, filter: nil, includes: nil, order: nil, &block)
|
50
58
|
tables = @tables
|
51
|
-
|
52
|
-
|
53
|
-
|
59
|
+
param_list = []
|
60
|
+
param_list << filter.map {|k,v| "#{k}=#{v}" } if filter
|
61
|
+
param_list << "order=#{[order].flatten.join(?,)}" if order
|
62
|
+
param_list << "includes=#{includes}" if includes
|
63
|
+
params = ?? + param_list.join(?&) if param_list.length > 0
|
54
64
|
Menilite::Http.get_json("api/#{model_class}#{params}") do
|
55
65
|
on :success do |json|
|
56
66
|
tables[model_class] = json.map {|value| [value[:id], Menilite::Deserializer.deserialize(model_class, value, includes)] }.to_h
|
@@ -64,7 +74,22 @@ module Menilite
|
|
64
74
|
end
|
65
75
|
end
|
66
76
|
|
67
|
-
def delete(
|
77
|
+
def delete(model_class, filter:, &block)
|
78
|
+
tables = @tables
|
79
|
+
Menilite::Http.request_json("api/#{model_class}", :delete, filter) do
|
80
|
+
on :success do |json|
|
81
|
+
res = json.map {|value| tables[model_class].delete(value[:id]) }
|
82
|
+
block.call res if block
|
83
|
+
end
|
84
|
+
|
85
|
+
on :failure do |res|
|
86
|
+
puts ">> Error: #{res.error}"
|
87
|
+
puts ">>>> delete: #{model.inspect}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def delete_all(mdoel_class)
|
68
93
|
@tables[model_class] = {}
|
69
94
|
end
|
70
95
|
|
data/lib/menilite/model.rb
CHANGED
@@ -81,6 +81,10 @@ module Menilite
|
|
81
81
|
self.save(&block)
|
82
82
|
end
|
83
83
|
|
84
|
+
def delete!(&block)
|
85
|
+
self.class.delete(self.id, &block)
|
86
|
+
end
|
87
|
+
|
84
88
|
def on(event, *field_names, &block)
|
85
89
|
field_names.each {|file_name| set_listener(event, file_name, &block) }
|
86
90
|
end
|
@@ -125,9 +129,14 @@ module Menilite
|
|
125
129
|
self.new(fields).save(&block)
|
126
130
|
end
|
127
131
|
|
132
|
+
def delete(id, &block)
|
133
|
+
self.init
|
134
|
+
store.delete(self, filter: {id: id}, &block)
|
135
|
+
end
|
136
|
+
|
128
137
|
def delete_all
|
129
138
|
self.init
|
130
|
-
store.
|
139
|
+
store.delete_all(self)
|
131
140
|
end
|
132
141
|
|
133
142
|
|
@@ -341,6 +350,7 @@ module Menilite
|
|
341
350
|
end
|
342
351
|
|
343
352
|
def convert_type(key, value)
|
353
|
+
return ["guid", value] if ["id", "guid"].include?(key.to_s)
|
344
354
|
field_info = self.field_info[key] || self.field_info[key.to_s.sub(/_id\z/,'').to_sym]
|
345
355
|
raise "no such field #{key} in #{self}" unless field_info
|
346
356
|
converted = case field_info.type
|
@@ -64,7 +64,15 @@ module Menilite
|
|
64
64
|
assoc.map {|ar| to_model(ar, model_class) } || []
|
65
65
|
end
|
66
66
|
|
67
|
-
def delete(model_class)
|
67
|
+
def delete(model_class, filter:)
|
68
|
+
assoc = @armodels[model_class].all
|
69
|
+
assoc = assoc.where(filter_condition(model_class, filter))
|
70
|
+
res = assoc.map {|ar| to_model(ar, model_class) } || []
|
71
|
+
assoc.delete_all
|
72
|
+
res
|
73
|
+
end
|
74
|
+
|
75
|
+
def delete_all(model_class)
|
68
76
|
@armodels[model_class].delete_all
|
69
77
|
end
|
70
78
|
|
@@ -114,6 +114,18 @@ module Menilite
|
|
114
114
|
json Serializer.serialize(results, includes)
|
115
115
|
end
|
116
116
|
|
117
|
+
delete "/#{resource_name}" do
|
118
|
+
PrivilegeService.init
|
119
|
+
router.before_action_handlers(klass, 'delete').each {|h| self.instance_eval(&h[:proc]) }
|
120
|
+
params = JSON.parse(request.body.read)
|
121
|
+
results = klass.fetch(filter: params).map do |model|
|
122
|
+
model.delete
|
123
|
+
model
|
124
|
+
end
|
125
|
+
|
126
|
+
json Serializer.serialize(results)
|
127
|
+
end
|
128
|
+
|
117
129
|
klass.action_info.each do |name, action|
|
118
130
|
path = action.options[:save] || action.options[:class] ? "/#{resource_name}/#{action.name}" : "/#{resource_name}/#{action.name}/:id"
|
119
131
|
|
data/lib/menilite/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: menilite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- youchan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -84,6 +84,14 @@ files:
|
|
84
84
|
- Rakefile
|
85
85
|
- bin/console
|
86
86
|
- bin/setup
|
87
|
+
- docs/articles/getting-started.md
|
88
|
+
- docs/articles/list.yaml
|
89
|
+
- docs/articles/model.md
|
90
|
+
- docs/css/milligram.min.css
|
91
|
+
- docs/css/style.css
|
92
|
+
- docs/index.html
|
93
|
+
- docs/src/build.rb
|
94
|
+
- docs/views/index.haml
|
87
95
|
- lib/menilite.rb
|
88
96
|
- lib/menilite/client/deserializer.rb
|
89
97
|
- lib/menilite/client/http.rb
|