jason-rails 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/client/lib/JasonContext.d.ts +2 -0
- data/client/lib/JasonContext.js +5 -0
- data/client/lib/JasonProvider.d.ts +7 -0
- data/client/lib/JasonProvider.js +109 -0
- data/client/lib/actionFactory.d.ts +5 -0
- data/client/lib/actionFactory.js +33 -0
- data/client/lib/createActions.d.ts +2 -0
- data/client/lib/createActions.js +46 -0
- data/client/lib/createJasonReducers.d.ts +1 -0
- data/client/lib/createJasonReducers.js +36 -0
- data/client/lib/createPayloadHandler.d.ts +1 -0
- data/client/lib/createPayloadHandler.js +87 -0
- data/client/lib/index.d.ts +10 -0
- data/client/lib/index.js +12 -0
- data/client/lib/makeEager.d.ts +1 -0
- data/client/lib/makeEager.js +51 -0
- data/client/lib/useAct.d.ts +1 -0
- data/client/lib/useAct.js +12 -0
- data/client/lib/useSub.d.ts +1 -0
- data/client/lib/useSub.js +14 -0
- data/client/package.json +27 -0
- data/client/src/JasonContext.ts +5 -0
- data/client/src/JasonProvider.tsx +108 -0
- data/client/src/actionFactory.ts +34 -0
- data/client/src/createActions.ts +50 -0
- data/client/src/createJasonReducers.ts +34 -0
- data/client/src/createPayloadHandler.ts +95 -0
- data/client/src/index.ts +7 -0
- data/client/src/makeEager.ts +46 -0
- data/client/src/useAct.ts +9 -0
- data/client/src/useSub.ts +10 -0
- data/client/tsconfig.json +15 -0
- data/client/yarn.lock +140 -0
- data/jason-rails.gemspec +25 -0
- data/lib/jason.rb +10 -0
- data/lib/jason/api_model.rb +47 -0
- data/lib/jason/channel.rb +37 -0
- data/lib/jason/publisher.rb +79 -0
- data/lib/jason/subscription.rb +172 -0
- data/lib/jason/version.rb +3 -0
- metadata +96 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'
|
2
|
+
import pluralize from 'pluralize'
|
3
|
+
import _ from 'lodash'
|
4
|
+
|
5
|
+
function generateSlices(schema) {
|
6
|
+
const sliceNames = schema.map(k => pluralize(k))
|
7
|
+
const adapter = createEntityAdapter()
|
8
|
+
|
9
|
+
return _.fromPairs(_.map(sliceNames, name => {
|
10
|
+
return [name, createSlice({
|
11
|
+
name,
|
12
|
+
initialState: adapter.getInitialState(),
|
13
|
+
reducers: {
|
14
|
+
upsert: adapter.upsertOne,
|
15
|
+
upsertMany: adapter.upsertMany,
|
16
|
+
add: adapter.addOne,
|
17
|
+
setAll: adapter.setAll,
|
18
|
+
remove: adapter.removeOne,
|
19
|
+
movePriority: (s, { payload: { id, priority, parentFilter } }) => {
|
20
|
+
// Get IDs and insert our item at the new index
|
21
|
+
var affectedIds = _.orderBy(_.filter(_.values(s.entities), parentFilter).filter(e => e.id !== id), 'priority').map(e => e.id)
|
22
|
+
affectedIds.splice(priority, 0, id)
|
23
|
+
|
24
|
+
// Apply update
|
25
|
+
affectedIds.forEach((id, i) => (s.entities[id] as any).priority = i)
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}).reducer]
|
29
|
+
}))
|
30
|
+
}
|
31
|
+
|
32
|
+
export default function createJasonReducers(schema) {
|
33
|
+
return generateSlices(_.keys(schema))
|
34
|
+
}
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import { apply_patch } from 'jsonpatch'
|
2
|
+
import { camelizeKeys } from 'humps'
|
3
|
+
import pluralize from 'pluralize'
|
4
|
+
import _ from 'lodash'
|
5
|
+
|
6
|
+
function diffSeconds(dt2, dt1) {
|
7
|
+
var diff =(dt2.getTime() - dt1.getTime()) / 1000
|
8
|
+
return Math.abs(Math.round(diff))
|
9
|
+
}
|
10
|
+
|
11
|
+
export default function createPayloadHandler(dispatch, subscription, model, config) {
|
12
|
+
console.log({ model, config })
|
13
|
+
let payload = {}
|
14
|
+
let idx = 0
|
15
|
+
let patchQueue = {}
|
16
|
+
|
17
|
+
let lastCheckAt = new Date()
|
18
|
+
let updateDeadline = null as Date | null
|
19
|
+
let checkInterval
|
20
|
+
|
21
|
+
function getPayload() {
|
22
|
+
console.log({ getPayload: model, subscription })
|
23
|
+
subscription.send({ getPayload: { model, config } })
|
24
|
+
}
|
25
|
+
|
26
|
+
const tGetPayload = _.throttle(getPayload, 10000)
|
27
|
+
|
28
|
+
function dispatchPayload() {
|
29
|
+
const includeModels = (config.includeModels || []).map(m => _.camelCase(m))
|
30
|
+
|
31
|
+
console.log("Dispatching", { payload, includeModels })
|
32
|
+
|
33
|
+
includeModels.forEach(m => {
|
34
|
+
const subPayload = _.flatten(_.compact(camelizeKeys(payload).map(instance => instance[m])))
|
35
|
+
console.log({ type: `${pluralize(m)}/upsertMany`, payload: subPayload })
|
36
|
+
dispatch({ type: `${pluralize(m)}/upsertMany`, payload: subPayload })
|
37
|
+
})
|
38
|
+
|
39
|
+
dispatch({ type: `${pluralize(model)}/upsertMany`, payload: camelizeKeys(payload) })
|
40
|
+
}
|
41
|
+
|
42
|
+
function processQueue() {
|
43
|
+
console.log({ idx, patchQueue })
|
44
|
+
lastCheckAt = new Date()
|
45
|
+
if (patchQueue[idx]) {
|
46
|
+
payload = apply_patch(payload, patchQueue[idx])
|
47
|
+
if (patchQueue[idx]) {
|
48
|
+
dispatchPayload()
|
49
|
+
}
|
50
|
+
delete patchQueue[idx]
|
51
|
+
idx++
|
52
|
+
updateDeadline = null
|
53
|
+
processQueue()
|
54
|
+
// If there are updates in the queue that are ahead of the index, some have arrived out of order
|
55
|
+
// Set a deadline for new updates before it declares the update missing and refetches.
|
56
|
+
} else if (_.keys(patchQueue).length > 0 && !updateDeadline) {
|
57
|
+
var t = new Date()
|
58
|
+
t.setSeconds(t.getSeconds() + 3)
|
59
|
+
updateDeadline = t
|
60
|
+
setTimeout(processQueue, 3100)
|
61
|
+
// If more than 10 updates in queue, or deadline has passed, restart
|
62
|
+
} else if (_.keys(patchQueue).length > 10 || (updateDeadline && diffSeconds(updateDeadline, new Date()) < 0)) {
|
63
|
+
tGetPayload()
|
64
|
+
updateDeadline = null
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
function handlePayload(data) {
|
69
|
+
const { value, idx: newIdx, diff, latency, type } = data
|
70
|
+
console.log({ data })
|
71
|
+
|
72
|
+
if (type === 'payload') {
|
73
|
+
if (!value) return null;
|
74
|
+
|
75
|
+
payload = value
|
76
|
+
dispatchPayload()
|
77
|
+
idx = newIdx + 1
|
78
|
+
// Clear any old changes left in the queue
|
79
|
+
patchQueue= _.pick(patchQueue, _.keys(patchQueue).filter(k => k > newIdx + 1))
|
80
|
+
return
|
81
|
+
}
|
82
|
+
|
83
|
+
patchQueue[newIdx] = diff
|
84
|
+
|
85
|
+
processQueue()
|
86
|
+
|
87
|
+
if (diffSeconds((new Date()), lastCheckAt) >= 3) {
|
88
|
+
lastCheckAt = new Date()
|
89
|
+
console.log('Interval lost. Pulling from server')
|
90
|
+
tGetPayload()
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
return handlePayload
|
95
|
+
}
|
data/client/src/index.ts
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
import pluralize from 'pluralize'
|
2
|
+
import _ from 'lodash'
|
3
|
+
import { useSelector } from 'react-redux'
|
4
|
+
|
5
|
+
export default function (schema) {
|
6
|
+
function addRelations(s, objects, objectType, relations) {
|
7
|
+
// first find out relation name
|
8
|
+
if (_.isArray(relations)) {
|
9
|
+
relations.forEach(relation => {
|
10
|
+
objects = addRelations(s, objects, objectType, relation)
|
11
|
+
})
|
12
|
+
} else if (typeof(relations) === 'object') {
|
13
|
+
const relation = Object.keys(relations)[0]
|
14
|
+
const subRelations = relations[relation]
|
15
|
+
|
16
|
+
objects = addRelations(s, objects, objectType, relation)
|
17
|
+
objects[relation] = addRelations(s, objects[relation], pluralize(relation), subRelations)
|
18
|
+
// #
|
19
|
+
} else if (typeof(relations) === 'string') {
|
20
|
+
const relation = relations
|
21
|
+
if (_.isArray(objects)) {
|
22
|
+
objects = objects.map(obj => addRelations(s, obj, objectType, relation))
|
23
|
+
} else {
|
24
|
+
const relatedObjects = _.values(s[pluralize(relation)].entities)
|
25
|
+
|
26
|
+
if(pluralize.isSingular(relation)) {
|
27
|
+
objects = { ...objects, [relation]: _.find(relatedObjects, { id: objects[relation + 'Id'] }) }
|
28
|
+
} else {
|
29
|
+
objects = { ...objects, [relation]: relatedObjects.filter(e => e[pluralize.singular(objectType) + 'Id'] === objects.id) }
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
return objects
|
35
|
+
}
|
36
|
+
|
37
|
+
function useEager(entity, id = null, relations = []) {
|
38
|
+
if (id) {
|
39
|
+
return useSelector(s => addRelations(s, { ...s[entity].entities[String(id)] }, entity, relations))
|
40
|
+
} else {
|
41
|
+
return useSelector(s => addRelations(s, _.values(s[entity].entities), entity, relations))
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
return useEager
|
46
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"target": "es2015",
|
4
|
+
"module": "es2015",
|
5
|
+
"module": "commonjs",
|
6
|
+
"declaration": true,
|
7
|
+
"outDir": "./lib",
|
8
|
+
"strict": true,
|
9
|
+
"noImplicitAny": false,
|
10
|
+
"jsx": "react",
|
11
|
+
"esModuleInterop": true
|
12
|
+
},
|
13
|
+
"include": ["src"],
|
14
|
+
"exclude": ["node_modules", "**/__tests__/*"]
|
15
|
+
}
|
data/client/yarn.lock
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
2
|
+
# yarn lockfile v1
|
3
|
+
|
4
|
+
|
5
|
+
"@rails/actioncable@^6.0.3-4":
|
6
|
+
version "6.0.3-4"
|
7
|
+
resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.0.3-4.tgz#f17c0ef2235d1624d6052b749005608260bd55ef"
|
8
|
+
integrity sha512-uie5McTpl69vHnXCVzKj7iYpVKFfLuE7aqul/I7MX5zVd+yVyyC/g75T1Q10GofyqHYNYWgPiIxgQIoYPyyeKw==
|
9
|
+
|
10
|
+
axios-case-converter@^0.6.0:
|
11
|
+
version "0.6.0"
|
12
|
+
resolved "https://registry.yarnpkg.com/axios-case-converter/-/axios-case-converter-0.6.0.tgz#7a99120138046ad6faaf1fc2b638fea0fe63f26f"
|
13
|
+
integrity sha512-mlpaFFTBlv+o+NL2YPSWfC8BQv3qUesxTYD0N11/8dgrg0aDbxUaAglromCBI+0NUcfenM42xMGEUhzTtWZqKg==
|
14
|
+
dependencies:
|
15
|
+
camel-case "^4.1.1"
|
16
|
+
header-case "^2.0.3"
|
17
|
+
snake-case "^3.0.3"
|
18
|
+
|
19
|
+
axios@^0.21.0:
|
20
|
+
version "0.21.0"
|
21
|
+
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca"
|
22
|
+
integrity sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==
|
23
|
+
dependencies:
|
24
|
+
follow-redirects "^1.10.0"
|
25
|
+
|
26
|
+
blueimp-md5@^2.18.0:
|
27
|
+
version "2.18.0"
|
28
|
+
resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.18.0.tgz#1152be1335f0c6b3911ed9e36db54f3e6ac52935"
|
29
|
+
integrity sha512-vE52okJvzsVWhcgUHOv+69OG3Mdg151xyn41aVQN/5W5S+S43qZhxECtYLAEHMSFWX6Mv5IZrzj3T5+JqXfj5Q==
|
30
|
+
|
31
|
+
camel-case@^4.1.1:
|
32
|
+
version "4.1.2"
|
33
|
+
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
|
34
|
+
integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
|
35
|
+
dependencies:
|
36
|
+
pascal-case "^3.1.2"
|
37
|
+
tslib "^2.0.3"
|
38
|
+
|
39
|
+
capital-case@^1.0.4:
|
40
|
+
version "1.0.4"
|
41
|
+
resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669"
|
42
|
+
integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==
|
43
|
+
dependencies:
|
44
|
+
no-case "^3.0.4"
|
45
|
+
tslib "^2.0.3"
|
46
|
+
upper-case-first "^2.0.2"
|
47
|
+
|
48
|
+
dot-case@^3.0.4:
|
49
|
+
version "3.0.4"
|
50
|
+
resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
|
51
|
+
integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
|
52
|
+
dependencies:
|
53
|
+
no-case "^3.0.4"
|
54
|
+
tslib "^2.0.3"
|
55
|
+
|
56
|
+
follow-redirects@^1.10.0:
|
57
|
+
version "1.13.0"
|
58
|
+
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
59
|
+
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
60
|
+
|
61
|
+
header-case@^2.0.3:
|
62
|
+
version "2.0.4"
|
63
|
+
resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063"
|
64
|
+
integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==
|
65
|
+
dependencies:
|
66
|
+
capital-case "^1.0.4"
|
67
|
+
tslib "^2.0.3"
|
68
|
+
|
69
|
+
humps@^2.0.1:
|
70
|
+
version "2.0.1"
|
71
|
+
resolved "https://registry.yarnpkg.com/humps/-/humps-2.0.1.tgz#dd02ea6081bd0568dc5d073184463957ba9ef9aa"
|
72
|
+
integrity sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao=
|
73
|
+
|
74
|
+
jsonpatch@^3.0.1:
|
75
|
+
version "3.0.1"
|
76
|
+
resolved "https://registry.yarnpkg.com/jsonpatch/-/jsonpatch-3.0.1.tgz#97225367c1c3c5bf1641be59b2f73be19759f06f"
|
77
|
+
integrity sha1-lyJTZ8HDxb8WQb5Zsvc74ZdZ8G8=
|
78
|
+
|
79
|
+
lodash@^4.17.20:
|
80
|
+
version "4.17.20"
|
81
|
+
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
82
|
+
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
|
83
|
+
|
84
|
+
lower-case@^2.0.2:
|
85
|
+
version "2.0.2"
|
86
|
+
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
|
87
|
+
integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
|
88
|
+
dependencies:
|
89
|
+
tslib "^2.0.3"
|
90
|
+
|
91
|
+
no-case@^3.0.4:
|
92
|
+
version "3.0.4"
|
93
|
+
resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
|
94
|
+
integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
|
95
|
+
dependencies:
|
96
|
+
lower-case "^2.0.2"
|
97
|
+
tslib "^2.0.3"
|
98
|
+
|
99
|
+
pascal-case@^3.1.2:
|
100
|
+
version "3.1.2"
|
101
|
+
resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
|
102
|
+
integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
|
103
|
+
dependencies:
|
104
|
+
no-case "^3.0.4"
|
105
|
+
tslib "^2.0.3"
|
106
|
+
|
107
|
+
pluralize@^8.0.0:
|
108
|
+
version "8.0.0"
|
109
|
+
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
|
110
|
+
integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
|
111
|
+
|
112
|
+
snake-case@^3.0.3:
|
113
|
+
version "3.0.4"
|
114
|
+
resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"
|
115
|
+
integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
|
116
|
+
dependencies:
|
117
|
+
dot-case "^3.0.4"
|
118
|
+
tslib "^2.0.3"
|
119
|
+
|
120
|
+
tslib@^2.0.3:
|
121
|
+
version "2.0.3"
|
122
|
+
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"
|
123
|
+
integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==
|
124
|
+
|
125
|
+
typescript@^4.1.2:
|
126
|
+
version "4.1.2"
|
127
|
+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9"
|
128
|
+
integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==
|
129
|
+
|
130
|
+
upper-case-first@^2.0.2:
|
131
|
+
version "2.0.2"
|
132
|
+
resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324"
|
133
|
+
integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==
|
134
|
+
dependencies:
|
135
|
+
tslib "^2.0.3"
|
136
|
+
|
137
|
+
uuid@^8.3.1:
|
138
|
+
version "8.3.1"
|
139
|
+
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31"
|
140
|
+
integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==
|
data/jason-rails.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'lib/jason/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "jason-rails"
|
5
|
+
spec.version = Jason::VERSION
|
6
|
+
spec.authors = ["James Rees"]
|
7
|
+
spec.email = ["jarees@gmail.com"]
|
8
|
+
|
9
|
+
spec.summary = "Reactive user interfaces with minimal boilerplate, using Rails + Redux"
|
10
|
+
spec.homepage = "https://github.com/jamesr2323/jason"
|
11
|
+
spec.license = "MIT"
|
12
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
13
|
+
|
14
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
15
|
+
spec.metadata["source_code_uri"] = "https://github.com/jamesr2323/jason"
|
16
|
+
spec.metadata["changelog_uri"] = "https://github.com/jamesr2323/jason"
|
17
|
+
|
18
|
+
# Specify which files should be added to the gem when it is released.
|
19
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
21
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
|
+
end
|
23
|
+
spec.executables = []
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
end
|
data/lib/jason.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
class Jason::ApiModel
|
2
|
+
cattr_accessor :models
|
3
|
+
attr_accessor :model, :name
|
4
|
+
|
5
|
+
def self.configure(models)
|
6
|
+
@@models = models
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
@name = name
|
11
|
+
@model = OpenStruct.new(JASON_API_MODEL[name.to_sym])
|
12
|
+
end
|
13
|
+
|
14
|
+
def allowed_params
|
15
|
+
model.allowed_params || []
|
16
|
+
end
|
17
|
+
|
18
|
+
def include_models
|
19
|
+
model.include_models || []
|
20
|
+
end
|
21
|
+
|
22
|
+
def include_methods
|
23
|
+
model.include_methods || []
|
24
|
+
end
|
25
|
+
|
26
|
+
def priority_scope
|
27
|
+
model.priority_scope || []
|
28
|
+
end
|
29
|
+
|
30
|
+
def subscribed_fields
|
31
|
+
model.subscribed_fields || []
|
32
|
+
end
|
33
|
+
|
34
|
+
def scope
|
35
|
+
model.scope
|
36
|
+
end
|
37
|
+
|
38
|
+
def as_json_config
|
39
|
+
include_configs = include_models.map do |assoc|
|
40
|
+
reflection = name.classify.constantize.reflect_on_association(assoc.to_sym)
|
41
|
+
api_model = Jason::ApiModel.new(reflection.klass.name.underscore)
|
42
|
+
{ assoc => { only: api_model.subscribed_fields, methods: api_model.include_methods } }
|
43
|
+
end
|
44
|
+
|
45
|
+
{ only: subscribed_fields, include: include_configs, methods: include_methods }
|
46
|
+
end
|
47
|
+
end
|