picatrix 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -2
- data/lib/picatrix/digraph_parser.rb +9 -18
- data/lib/picatrix/generated/app.rb +79 -69
- data/lib/picatrix/generated/view_submission.rb +3 -0
- data/lib/picatrix/jenny.rb +50 -34
- data/lib/picatrix/pacman.rb +4 -2
- data/lib/picatrix/templates/app.rb +34 -19
- data/lib/picatrix/templates/mason/view_submission.json +12 -7
- data/lib/picatrix/templates/mason/view_submission_min.json +2 -2
- data/lib/picatrix/templates/mason/view_submissions.json +9 -5
- data/lib/picatrix/templates/type.rb +3 -0
- data/lib/picatrix/transform_to_hash.rb +0 -5
- data/lib/picatrix/version.rb +1 -1
- metadata +2 -3
- data/lib/picatrix/generated/.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1526c5c727bb983c60d9c3240984054c96187de
|
4
|
+
data.tar.gz: 6af84973981466c805aa680fad9ca915353418f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3feed7709d09d6b5bd06d3d88cc09de6a054bee63d24dd9cf62c01f80f356fbb0cdb20f6530c9b950f8c2fc8320273020ebeaae6892fbfc2ad7e51362c021d6
|
7
|
+
data.tar.gz: 7f399c285ac1dde603ca580a3fdc2fe2fca415bc17dd24ef3a75f4ea2cfe5cd5b31c56175edc1840817349fc41c51e4ebce3ddbd16559ba09d340a3360ee7b94
|
data/README.md
CHANGED
@@ -10,7 +10,16 @@
|
|
10
10
|
An opinionated hypermedia API generator.
|
11
11
|
|
12
12
|
Requires:
|
13
|
-
- valid `.dot` file
|
13
|
+
- valid `.dot` file with the following additional style guidelines
|
14
|
+
- edge style defaults to `arrowhead="odiamond"` to signify default requests are `GET`
|
15
|
+
- the first node listed should be the root, and is signified by `xlabel=` and `shape=point`
|
16
|
+
- collection nodes should be given `shape=folder` and pluralized
|
17
|
+
- the item node belonging to the collection node should be its singularized version and `shape=rectangle`
|
18
|
+
- forms (often called templates in the code, because they are a template for a valid request to the server) are given a `_template` suffix and `shape=note`
|
19
|
+
- `style=dotted` means the related object will be represented inline (embedded)
|
20
|
+
- `style=bold` and `arrowhead=normal` means `POST`
|
21
|
+
- `arrowhead=normal` alone means `PATCH`
|
22
|
+
- `color=red fontcolor=red` means `DELETE`
|
14
23
|
|
15
24
|
Outputs:
|
16
25
|
- Sinatra style routes
|
@@ -21,7 +30,7 @@ Outputs:
|
|
21
30
|
|
22
31
|
## About
|
23
32
|
|
24
|
-
Directed graphs get complicated, but can be
|
33
|
+
Directed graphs get complicated, but can be divided into simpler subgraphs. Picatrix is currently useful for only a single workflow (and barely that right now, as we're way before a real release). Integrated workflows will involve generating several route sets that will be required into a single Sinatra app. Some workflows may even be representable as DAGs/trees.
|
25
34
|
|
26
35
|
The ideal way to use Picatrix is to do an exercise in designing your API "outside in" where all inputs/outputs are defined, and a state diagram is drawn. This diagram can be translated to a dot file, and the inputs/outputs can be translated into hypermedia assets.
|
27
36
|
|
@@ -57,6 +66,14 @@ $ bin/picapica dg_api.dot app_name
|
|
57
66
|
|
58
67
|
![state diagram image of sample app](spec/support/dg_api.dot.png "simple photo viewing app")
|
59
68
|
|
69
|
+
### how to interpret the graph
|
70
|
+
|
71
|
+
Nodes and edges translate roughly into application and/or resource states, and state transitions.
|
72
|
+
|
73
|
+
Dotted lines represent inlined relations. So, `View submissions` inlines `View submission` by `:item_id` (in this example a number).
|
74
|
+
|
75
|
+
Labels on edges are link relations. Confusingly the actual _URL_ of the state transition (moving to the next state) is still the target node (essentially, think of the state transition name as the same as the name of the ideal output) _and_ its link relation to its source. So, `A (make_B_do_x)-> B` is `B/make_B_do_x`. This is still (obviously) sketchy.
|
76
|
+
|
60
77
|
## Development
|
61
78
|
|
62
79
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -13,11 +13,7 @@ module Picatrix
|
|
13
13
|
rule(:default_definitions) do
|
14
14
|
indent >>
|
15
15
|
str("edge [") >>
|
16
|
-
|
17
|
-
indent.repeat >>
|
18
|
-
str("arrowhead=\"odiamond\"") >>
|
19
|
-
newline >>
|
20
|
-
indent >>
|
16
|
+
(str("]").absent? >> any).repeat(0) >>
|
21
17
|
str("]") >>
|
22
18
|
newline
|
23
19
|
end
|
@@ -34,8 +30,8 @@ module Picatrix
|
|
34
30
|
end
|
35
31
|
rule(:style) do
|
36
32
|
str("style=dotted") |
|
37
|
-
|
38
|
-
|
33
|
+
str("style=bold") |
|
34
|
+
delete_marker
|
39
35
|
end
|
40
36
|
rule(:post_marker) do
|
41
37
|
str("arrowhead=normal")
|
@@ -45,8 +41,8 @@ module Picatrix
|
|
45
41
|
end
|
46
42
|
rule(:shape) do
|
47
43
|
str("shape=note") |
|
48
|
-
|
49
|
-
|
44
|
+
str("shape=folder") |
|
45
|
+
str("shape=rectangle")
|
50
46
|
end
|
51
47
|
rule(:label) do
|
52
48
|
str("[") >>
|
@@ -77,16 +73,12 @@ module Picatrix
|
|
77
73
|
space.repeat(0) >>
|
78
74
|
str("}")
|
79
75
|
end
|
80
|
-
rule(:root_label) do
|
81
|
-
str("[xlabel=") >>
|
82
|
-
(str("shape=point]").absent? >> any).repeat >>
|
83
|
-
str("shape=point]")
|
84
|
-
end
|
85
76
|
rule(:root_line) do
|
86
77
|
indent >>
|
87
|
-
|
78
|
+
str("root") >>
|
88
79
|
space >>
|
89
|
-
|
80
|
+
(newline.absent? >> any).repeat(0) >>
|
81
|
+
newline
|
90
82
|
end
|
91
83
|
rule(:digraph_open_tag) { str("digraph d {") }
|
92
84
|
rule(:digraph_close_tag) { str("}") >> newline.repeat(0) >> eof }
|
@@ -100,8 +92,7 @@ module Picatrix
|
|
100
92
|
root_of_api
|
101
93
|
end
|
102
94
|
rule(:root_of_api) do
|
103
|
-
root_line
|
104
|
-
newline.repeat(1) >>
|
95
|
+
root_line >>
|
105
96
|
(
|
106
97
|
digraph_close_tag.absent? >>
|
107
98
|
(
|
@@ -7,82 +7,92 @@ require_all("./lib/picatrix/generated/*.rb")
|
|
7
7
|
class App < Sinatra::Base
|
8
8
|
set :public_folder => "public", :static => true
|
9
9
|
|
10
|
+
get '/rels' do
|
11
|
+
json([{"root"=>{:target=>"view_submissions", :link_relation=>"\"newest\"", :inline=>false, :method=>:get}}, {"view_submissions"=>{:target=>"view_submission", :link_relation=>"\":item_id\"", :inline=>true, :method=>:get}}, {"view_submissions"=>{:target=>"submission_filter_template", :link_relation=>"\"filter\"", :inline=>true, :method=>:get}}, {"submission_filter_template"=>{:target=>"view_submissions", :link_relation=>"\"filter\"", :inline=>false, :method=>:get}}, {"view_submissions"=>{:target=>"submission_add_template", :link_relation=>"\"add\"", :inline=>true, :method=>:get}}, {"submission_add_template"=>{:target=>"view_submission", :link_relation=>"\"submit\"", :inline=>false, :method=>:post}}, {"view_submission"=>{:target=>"view_submissions", :link_relation=>"\"newest\"", :inline=>false, :method=>:get}}, {"view_submission"=>{:target=>"submission_delete_template", :link_relation=>"\"remove\"", :inline=>true, :method=>:get}}, {"submission_delete_template"=>{:target=>"view_submissions", :link_relation=>"\"newest\"", :inline=>false, :method=>:delete}}, {"view_submission"=>{:target=>"submission_edit_template", :link_relation=>"\"edit\"", :inline=>true, :method=>:get}}, {"submission_edit_template"=>{:target=>"view_submission", :link_relation=>"\"self\"", :inline=>false, :method=>:patch}}])
|
12
|
+
end
|
13
|
+
|
10
14
|
get '/' do
|
11
|
-
status, headers, body = call env.merge("PATH_INFO" => "/
|
15
|
+
status, headers, body = call env.merge("PATH_INFO" => "/view_submissions/newest")
|
12
16
|
[status, headers, body]
|
13
17
|
end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
get "/view_submissions/newest" do
|
22
|
+
# get collection
|
23
|
+
items = ViewSubmission.all
|
24
|
+
# render collection into templates
|
25
|
+
hashed_items = items.collect do |item|
|
26
|
+
{"@controls"=>{"self"=>{"title"=>"submission #{item.id}", "href"=>"http://localhost:9292/view_submission/#{item.id}"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"}
|
27
|
+
end
|
28
|
+
# return that collection
|
29
|
+
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@namespaces"=>{"s"=>{"name"=>"http://localhost:9292/rels#"}}, "@controls"=>{"self"=>{"href"=>"http://localhost:9292/view_submissions/newest"}, "s:filter"=>{"href"=>"http://localhost:9292/view_submissions/filter?category={category}&has_photo={has_photo}", "isHrefTemplate"=>true, "title"=>"filter submissions by category", "description"=>"in addition to category, you can ensure the submission has a photo"}, "s:add"=>{"title"=>"add new submission", "encoding"=>"json", "href"=>"http://localhost:9292/submission_add_template/submit", "method"=>"POST", "template"=>{"title"=>"default title", "category"=>"cats", "photo_url"=>"http://cats.com"}}}}.merge({"view_submissions" => hashed_items}))
|
30
|
+
end
|
14
31
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
items = ViewSubmission.all
|
28
|
-
hashed_items = items.collect do |item|
|
29
|
-
item_id = item.id
|
30
|
-
category = item.category
|
31
|
-
photo = item.photo
|
32
|
-
{"@controls"=>{"self"=>{"title"=>"submission #{item_id}", "href"=>"http://localhost:9292/view_submission/#{item_id}"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"}
|
33
|
-
end
|
34
|
-
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@controls"=>{"self"=>{"href"=>"http://localhost:9292/welcome/newest"}, "is:filter"=>{"href"=>"http://localhost:9292/submission_filter_template/filter?category={category}&has_photo={has_photo}", "isHrefTemplate"=>true, "title"=>"filter submissions by category", "description"=>"in addition to category, you can ensure the submission has a photo"}, "is:add"=>{"title"=>"add new submission", "encoding"=>"json", "href"=>"http://localhost:9292/submission_add_template/submit", "method"=>"POST", "template"=>{"title"=>"default title", "category"=>"cats", "photo_url"=>"http://cats.com"}}}, "category"=>"#{params[:category]}", "has_photo"=>"#{params[:has_photo]}"}.merge({"view_submissions" => hashed_items}))
|
35
|
-
end
|
36
|
-
|
37
|
-
post "/submission_add_template/submit" do
|
38
|
-
items = ViewSubmission.all
|
39
|
-
hashed_items = items.collect do |item|
|
40
|
-
item_id = item.id
|
41
|
-
category = item.category
|
42
|
-
photo = item.photo
|
43
|
-
{"@controls"=>{"self"=>{"title"=>"submission #{item_id}", "href"=>"http://localhost:9292/view_submission/#{item_id}"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"}
|
44
|
-
end
|
45
|
-
json({"@controls"=>{"self"=>{"title"=>"submission #{item_id}", "href"=>"http://localhost:9292/view_submission/#{item_id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/welcome/newest"}, "is:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "is:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"DELETE"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}", :message=>0}.merge({"view_submissions" => hashed_items}))
|
46
|
-
end
|
47
|
-
|
48
|
-
get "/view_submission/newest" do
|
49
|
-
items = ViewSubmission.all
|
50
|
-
hashed_items = items.collect do |item|
|
51
|
-
item_id = item.id
|
52
|
-
category = item.category
|
53
|
-
photo = item.photo
|
54
|
-
{"@controls"=>{"self"=>{"title"=>"submission #{item_id}", "href"=>"http://localhost:9292/view_submission/#{item_id}"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"}
|
55
|
-
end
|
56
|
-
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@controls"=>{"self"=>{"title"=>"submission #{item_id}", "href"=>"http://localhost:9292/view_submission/#{item_id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/welcome/newest"}, "is:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "is:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"DELETE"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"}.merge({"view_submissions" => hashed_items}))
|
57
|
-
end
|
32
|
+
|
33
|
+
|
34
|
+
get "/view_submissions/filter" do
|
35
|
+
# get collection
|
36
|
+
items = ViewSubmission.all
|
37
|
+
# render collection into templates
|
38
|
+
hashed_items = items.collect do |item|
|
39
|
+
{"@controls"=>{"self"=>{"title"=>"submission #{item.id}", "href"=>"http://localhost:9292/view_submission/#{item.id}"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"}
|
40
|
+
end
|
41
|
+
# return that collection
|
42
|
+
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@namespaces"=>{"s"=>{"name"=>"http://localhost:9292/rels#"}}, "@controls"=>{"self"=>{"href"=>"http://localhost:9292/view_submissions/newest"}, "s:filter"=>{"href"=>"http://localhost:9292/view_submissions/filter?category={category}&has_photo={has_photo}", "isHrefTemplate"=>true, "title"=>"filter submissions by category", "description"=>"in addition to category, you can ensure the submission has a photo"}, "s:add"=>{"title"=>"add new submission", "encoding"=>"json", "href"=>"http://localhost:9292/submission_add_template/submit", "method"=>"POST", "template"=>{"title"=>"default title", "category"=>"cats", "photo_url"=>"http://cats.com"}}}, "category"=>"#{params[:category]}", "has_photo"=>"#{params[:has_photo]}"}.merge({"view_submissions" => hashed_items}))
|
43
|
+
end
|
58
44
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@controls"=>{"self"=>{"href"=>"http://localhost:9292/welcome/newest"}, "is:filter"=>{"href"=>"http://localhost:9292/submission_filter_template/filter?category={category}&has_photo={has_photo}", "isHrefTemplate"=>true, "title"=>"filter submissions by category", "description"=>"in addition to category, you can ensure the submission has a photo"}, "is:add"=>{"title"=>"add new submission", "encoding"=>"json", "href"=>"http://localhost:9292/submission_add_template/submit", "method"=>"POST", "template"=>{"title"=>"default title", "category"=>"cats", "photo_url"=>"http://cats.com"}}}, :message=>0}.merge({"view_submissions" => hashed_items}))
|
68
|
-
end
|
45
|
+
|
46
|
+
|
47
|
+
post "/view_submission/submit" do
|
48
|
+
# create item
|
49
|
+
item = ViewSubmission.create(params)
|
50
|
+
# return new item
|
51
|
+
json({"@namespaces"=>{"s"=>{"name"=>"http://localhost:9292/rels#"}}, "@controls"=>{"self"=>{"title"=>"submission #{item.id}", "href"=>"http://localhost:9292/view_submission/#{item.id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/view_submissions/newest"}, "s:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item.id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "s:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item.id}", "method"=>"DELETE"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}", :message=>0})
|
52
|
+
end
|
69
53
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
54
|
+
|
55
|
+
|
56
|
+
get "/view_submissions/newest" do
|
57
|
+
# get collection
|
58
|
+
items = ViewSubmission.all
|
59
|
+
# render collection into templates
|
60
|
+
hashed_items = items.collect do |item|
|
61
|
+
{"@controls"=>{"self"=>{"title"=>"submission #{item.id}", "href"=>"http://localhost:9292/view_submission/#{item.id}"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"}
|
62
|
+
end
|
63
|
+
# return that collection
|
64
|
+
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@namespaces"=>{"s"=>{"name"=>"http://localhost:9292/rels#"}}, "@controls"=>{"self"=>{"title"=>"submission #{item.id}", "href"=>"http://localhost:9292/view_submission/#{item.id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/view_submissions/newest"}, "s:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item.id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "s:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item.id}", "method"=>"DELETE"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"}.merge({"view_submissions" => hashed_items}))
|
65
|
+
end
|
80
66
|
|
67
|
+
|
68
|
+
|
69
|
+
delete "/view_submissions/newest" do
|
70
|
+
# get collection
|
71
|
+
items = ViewSubmission.all
|
72
|
+
# render collection into templates
|
73
|
+
hashed_items = items.collect do |item|
|
74
|
+
{"@controls"=>{"self"=>{"title"=>"submission #{item.id}", "href"=>"http://localhost:9292/view_submission/#{item.id}"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"}
|
75
|
+
end
|
76
|
+
# return that collection
|
77
|
+
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@namespaces"=>{"s"=>{"name"=>"http://localhost:9292/rels#"}}, "@controls"=>{"self"=>{"href"=>"http://localhost:9292/view_submissions/newest"}, "s:filter"=>{"href"=>"http://localhost:9292/view_submissions/filter?category={category}&has_photo={has_photo}", "isHrefTemplate"=>true, "title"=>"filter submissions by category", "description"=>"in addition to category, you can ensure the submission has a photo"}, "s:add"=>{"title"=>"add new submission", "encoding"=>"json", "href"=>"http://localhost:9292/submission_add_template/submit", "method"=>"POST", "template"=>{"title"=>"default title", "category"=>"cats", "photo_url"=>"http://cats.com"}}}, :message=>0}.merge({"view_submissions" => hashed_items}))
|
78
|
+
end
|
81
79
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
80
|
+
|
81
|
+
|
82
|
+
patch "/view_submission/self" do
|
83
|
+
# create item
|
84
|
+
item = ViewSubmission.find(params)
|
85
|
+
# return new item
|
86
|
+
json({"@namespaces"=>{"s"=>{"name"=>"http://localhost:9292/rels#"}}, "@controls"=>{"self"=>{"title"=>"submission #{item.id}", "href"=>"http://localhost:9292/view_submission/#{item.id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/view_submissions/newest"}, "s:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item.id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "s:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item.id}", "method"=>"DELETE"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}", :message=>0})
|
87
|
+
end
|
87
88
|
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
get "/view_submission/:item_id" do
|
93
|
+
item_id = params[:item_id]
|
94
|
+
item = ViewSubmission.find(item_id)
|
95
|
+
json({"@namespaces"=>{"s"=>{"name"=>"http://localhost:9292/rels#"}}, "@controls"=>{"self"=>{"title"=>"submission #{item.id}", "href"=>"http://localhost:9292/view_submission/#{item.id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/view_submissions/newest"}, "s:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item.id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "s:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item.id}", "method"=>"DELETE"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"})
|
96
|
+
end
|
97
|
+
|
88
98
|
end
|
data/lib/picatrix/jenny.rb
CHANGED
@@ -5,35 +5,39 @@ module Picatrix
|
|
5
5
|
class Jenny
|
6
6
|
include Thor::Base
|
7
7
|
include Thor::Actions
|
8
|
-
|
9
|
-
|
10
|
-
:
|
11
|
-
:generated
|
8
|
+
|
9
|
+
attr_accessor :app_name, :routes, :root_path, :rels,
|
10
|
+
:destination_stack, :options,
|
11
|
+
:default_response, :assets, :generated,
|
12
|
+
:addressable_items, :collectable_items
|
12
13
|
|
13
14
|
argument :name
|
14
15
|
source_root File.dirname(__FILE__)
|
15
16
|
|
16
17
|
def initialize(array = [], options = {}, app_name = "app")
|
17
|
-
|
18
|
+
# thor related
|
18
19
|
@options = options
|
19
20
|
@destination_stack = [self.class.source_root]
|
20
|
-
@default_response = { message: 0 }
|
21
21
|
|
22
22
|
hash = array.group_by {|e| e.keys.first}
|
23
23
|
@nodes = hash[:node].flat_map {|e| e[:node]}.reduce({}, :merge)
|
24
24
|
@edges = hash[:edge].flat_map {|e| e[:edge]}
|
25
|
-
|
26
|
-
@
|
25
|
+
|
26
|
+
@app_name = app_name
|
27
|
+
@rels = @edges
|
28
|
+
@default_response = { message: 0 }
|
27
29
|
|
28
30
|
@generated = []
|
29
|
-
# TODO for performance combine loops
|
30
31
|
@assets = assets
|
32
|
+
# items must come before collectable_items
|
31
33
|
@addressable_items = addressable_items
|
34
|
+
@collectable_items = collectable_items
|
32
35
|
@routes = routes
|
33
36
|
end
|
34
37
|
|
35
38
|
def just_do_it
|
36
39
|
@generated.each do |node_name|
|
40
|
+
# bring in defined objects
|
37
41
|
require "./lib/picatrix/generated/#{node_name}.rb"
|
38
42
|
end
|
39
43
|
generate_app_file
|
@@ -47,16 +51,12 @@ module Picatrix
|
|
47
51
|
)
|
48
52
|
end
|
49
53
|
def assets
|
50
|
-
@edges.collect do | edge|
|
54
|
+
@assets ||= @edges.collect do | edge|
|
51
55
|
source = edge.keys.first
|
52
56
|
properties = edge[source]
|
53
57
|
# if you dont have an inline asset, ignore
|
54
58
|
next unless properties[:inline]
|
55
59
|
|
56
|
-
# TODO ?
|
57
|
-
#link_relation = properties[:link_relation]
|
58
|
-
#path = "#{source}/#{link_relation.delete('"')}"
|
59
|
-
|
60
60
|
mason_path = "lib/picatrix/templates/mason/#{properties[:target]}.json"
|
61
61
|
|
62
62
|
if File.exist?(mason_path)
|
@@ -74,14 +74,20 @@ module Picatrix
|
|
74
74
|
end.compact.reduce({}, :merge)
|
75
75
|
end
|
76
76
|
def routes
|
77
|
-
@edges.collect do |edge|
|
77
|
+
@routes ||= @edges.collect do |edge|
|
78
78
|
source = edge.keys.first
|
79
|
+
target = edge.values.first[:target]
|
79
80
|
properties = edge[source]
|
81
|
+
|
80
82
|
# we dont need a route if it is inline represented
|
81
83
|
next if properties[:inline]
|
82
84
|
|
83
85
|
link_relation = properties[:link_relation]
|
84
|
-
path = "#{
|
86
|
+
path = "#{target}/#{link_relation.delete('"')}"
|
87
|
+
|
88
|
+
if source == "root"
|
89
|
+
@root_path = path
|
90
|
+
end
|
85
91
|
|
86
92
|
mason_path = "lib/picatrix/templates/mason/#{edge[source][:target]}.json"
|
87
93
|
|
@@ -95,36 +101,21 @@ module Picatrix
|
|
95
101
|
body = default_response
|
96
102
|
end
|
97
103
|
|
98
|
-
if source == root_node_name
|
99
|
-
@root = path
|
100
|
-
end
|
101
|
-
|
102
104
|
if (asset = assets[source]) && body.is_a?(Hash)
|
103
105
|
body.merge!(asset)
|
104
106
|
end
|
105
107
|
|
106
|
-
collections = @addressable_items.inject({}) do |memo, item|
|
107
|
-
memo["#{path}"] = {
|
108
|
-
name: "#{item[:type].pluralize}",
|
109
|
-
resource_name: "#{item[:type].camelcase}",
|
110
|
-
template: JSON.parse(
|
111
|
-
File.read("lib/picatrix/templates/mason/#{item[:type]}_min.json")
|
112
|
-
)
|
113
|
-
}
|
114
|
-
memo
|
115
|
-
end
|
116
|
-
|
117
108
|
{
|
118
109
|
path: path,
|
119
110
|
method: properties[:method],
|
120
111
|
# danger danger danger will robinson we are unescaping here!
|
121
112
|
body: body.to_s.delete("\\"),
|
122
|
-
collection:
|
113
|
+
collection: (collectable_items[target.singularize] || [])
|
123
114
|
}
|
124
115
|
end.compact!
|
125
116
|
end
|
126
117
|
def addressable_items
|
127
|
-
@nodes.collect do |node|
|
118
|
+
@addressable_items ||= @nodes.collect do |node|
|
128
119
|
node_name = node.first
|
129
120
|
node_properties = node.last
|
130
121
|
|
@@ -160,7 +151,6 @@ module Picatrix
|
|
160
151
|
else
|
161
152
|
schema = {}
|
162
153
|
end
|
163
|
-
|
164
154
|
{
|
165
155
|
path: item_path,
|
166
156
|
type: node_name,
|
@@ -171,5 +161,31 @@ module Picatrix
|
|
171
161
|
end
|
172
162
|
end.compact!
|
173
163
|
end
|
164
|
+
def collectable_items
|
165
|
+
@collectable_items ||= @addressable_items.inject({}) do |memo, item|
|
166
|
+
memo[item[:type]] = {
|
167
|
+
name: "#{item[:type].pluralize}",
|
168
|
+
resource_name: "#{item[:type].camelcase}",
|
169
|
+
template: JSON.parse(
|
170
|
+
File.read("lib/picatrix/templates/mason/#{item[:type]}_min.json")
|
171
|
+
)
|
172
|
+
}
|
173
|
+
memo
|
174
|
+
end
|
175
|
+
end
|
176
|
+
def return_mapping_of(method)
|
177
|
+
{
|
178
|
+
post: :single_return,
|
179
|
+
get: :collection_return,
|
180
|
+
patch: :single_return,
|
181
|
+
delete: :collection_return
|
182
|
+
}[method]
|
183
|
+
end
|
184
|
+
def send_method_for(method)
|
185
|
+
{
|
186
|
+
post: :create,
|
187
|
+
patch: :find
|
188
|
+
}[method]
|
189
|
+
end
|
174
190
|
end
|
175
191
|
end
|
data/lib/picatrix/pacman.rb
CHANGED
@@ -4,9 +4,11 @@ module Picatrix
|
|
4
4
|
attr_accessor :graph, :hash
|
5
5
|
|
6
6
|
def initialize(file_name)
|
7
|
-
@graph = GraphViz.parse(
|
7
|
+
@graph = GraphViz.parse(
|
8
|
+
file_name, :path => "/usr/local/bin"
|
9
|
+
)
|
8
10
|
@hash = TransformToHash.new.apply(
|
9
|
-
DigraphParser.new.
|
11
|
+
DigraphParser.new.parse_with_debug(
|
10
12
|
File.read(file_name)
|
11
13
|
)
|
12
14
|
).flat_map(&:entries).
|
@@ -7,27 +7,42 @@ require_all("./lib/picatrix/generated/*.rb")
|
|
7
7
|
class <%= @app_name.camelize %> < Sinatra::Base
|
8
8
|
set :public_folder => "public", :static => true
|
9
9
|
|
10
|
+
get '/rels' do
|
11
|
+
json(<%= @rels %>)
|
12
|
+
end
|
13
|
+
|
10
14
|
get '/' do
|
11
|
-
status, headers, body = call env.merge("PATH_INFO" => "/<%= @
|
15
|
+
status, headers, body = call env.merge("PATH_INFO" => "/<%= @root_path %>")
|
12
16
|
[status, headers, body]
|
13
17
|
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
18
|
+
|
19
|
+
<% @routes.uniq.each do |route| %>
|
20
|
+
<% if return_mapping_of(route[:method]) == :collection_return %>
|
21
|
+
<%= route[:method] %> "/<%= route[:path] %>" do
|
22
|
+
# get collection
|
23
|
+
items = <%= route[:collection][:resource_name].constantize %>.all
|
24
|
+
# render collection into templates
|
25
|
+
hashed_items = items.collect do |item|
|
26
|
+
<%= route[:collection][:template].to_s.delete("\\") %>
|
27
|
+
end
|
28
|
+
# return that collection
|
29
|
+
json(<%= route[:body] %>.merge({"<%= route[:collection][:name] %>" => hashed_items}))
|
30
|
+
end
|
31
|
+
<% else %>
|
32
|
+
<%= route[:method] %> "/<%= route[:path] %>" do
|
33
|
+
# create item
|
34
|
+
item = <%= route[:collection][:resource_name].constantize %>.<%= send_method_for(route[:method]).to_s %>(params)
|
35
|
+
# return new item
|
36
|
+
json(<%= route[:body] %>)
|
37
|
+
end
|
32
38
|
<% end %>
|
39
|
+
<% end %>
|
40
|
+
|
41
|
+
<% @addressable_items.each do |item| %>
|
42
|
+
get "/<%= item[:path] %>" do
|
43
|
+
item_id = params[:item_id]
|
44
|
+
item = <%= item[:type].camelcase.constantize %>.find(item_id)
|
45
|
+
json(<%= item[:body] %>)
|
46
|
+
end
|
47
|
+
<% end %>
|
33
48
|
end
|
@@ -1,26 +1,31 @@
|
|
1
1
|
{
|
2
|
+
"@namespaces": {
|
3
|
+
"s": {
|
4
|
+
"name": "http://localhost:9292/rels#"
|
5
|
+
}
|
6
|
+
},
|
2
7
|
"@controls": {
|
3
8
|
"self": {
|
4
|
-
"title": "submission #{
|
5
|
-
"href": "http://localhost:9292/view_submission/#{
|
9
|
+
"title": "submission #{item.id}",
|
10
|
+
"href": "http://localhost:9292/view_submission/#{item.id}"
|
6
11
|
},
|
7
12
|
"up": {
|
8
13
|
"title": "View submissions",
|
9
|
-
"href": "http://localhost:9292/
|
14
|
+
"href": "http://localhost:9292/view_submissions/newest"
|
10
15
|
},
|
11
|
-
"
|
16
|
+
"s:edit": {
|
12
17
|
"title": "update category or photo url",
|
13
18
|
"encoding": "json",
|
14
|
-
"href": "http://localhost:9292/view_submission/#{
|
19
|
+
"href": "http://localhost:9292/view_submission/#{item.id}",
|
15
20
|
"method": "PATCH",
|
16
21
|
"template": {
|
17
22
|
"photo": "{new_url}",
|
18
23
|
"category": "{new_category}"
|
19
24
|
}
|
20
25
|
},
|
21
|
-
"
|
26
|
+
"s:remove": {
|
22
27
|
"title": "remove submission",
|
23
|
-
"href": "http://localhost:9292/view_submission/#{
|
28
|
+
"href": "http://localhost:9292/view_submission/#{item.id}",
|
24
29
|
"method": "DELETE"
|
25
30
|
}
|
26
31
|
},
|
@@ -5,18 +5,22 @@
|
|
5
5
|
"@title": "Submissions",
|
6
6
|
"@description": "This resource represents submissions."
|
7
7
|
},
|
8
|
-
|
8
|
+
"@namespaces": {
|
9
|
+
"s": {
|
10
|
+
"name": "http://localhost:9292/rels#"
|
11
|
+
}
|
12
|
+
},
|
9
13
|
"@controls": {
|
10
14
|
"self": {
|
11
|
-
"href": "http://localhost:9292/
|
15
|
+
"href": "http://localhost:9292/view_submissions/newest"
|
12
16
|
},
|
13
|
-
"
|
14
|
-
"href": "http://localhost:9292/
|
17
|
+
"s:filter": {
|
18
|
+
"href": "http://localhost:9292/view_submissions/filter?category={category}&has_photo={has_photo}",
|
15
19
|
"isHrefTemplate": true,
|
16
20
|
"title": "filter submissions by category",
|
17
21
|
"description": "in addition to category, you can ensure the submission has a photo"
|
18
22
|
},
|
19
|
-
"
|
23
|
+
"s:add": {
|
20
24
|
"title": "add new submission",
|
21
25
|
"encoding": "json",
|
22
26
|
"href": "http://localhost:9292/submission_add_template/submit",
|
data/lib/picatrix/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: picatrix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Moore-Niemi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parslet
|
@@ -226,7 +226,6 @@ files:
|
|
226
226
|
- bin/setup
|
227
227
|
- lib/picatrix.rb
|
228
228
|
- lib/picatrix/digraph_parser.rb
|
229
|
-
- lib/picatrix/generated/.rb
|
230
229
|
- lib/picatrix/generated/app.rb
|
231
230
|
- lib/picatrix/generated/view_submission.rb
|
232
231
|
- lib/picatrix/jenny.rb
|
data/lib/picatrix/generated/.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'sinatra'
|
2
|
-
require 'sinatra/json'
|
3
|
-
require 'require_all'
|
4
|
-
|
5
|
-
require_all("./lib/picatrix/generated/*.rb")
|
6
|
-
|
7
|
-
class App < Sinatra::Base
|
8
|
-
set :public_folder => "public", :static => true
|
9
|
-
|
10
|
-
get '/' do
|
11
|
-
status, headers, body = call env.merge("PATH_INFO" => "/welcome/newest")
|
12
|
-
[status, headers, body]
|
13
|
-
end
|
14
|
-
|
15
|
-
get "/welcome/newest" do
|
16
|
-
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@controls"=>{"self"=>{"href"=>"http://localhost:9292/welcome/newest"}, "is:filter"=>{"href"=>"http://localhost:9292/submission_filter_template/filter?category={category}&has_photo={has_photo}", "isHrefTemplate"=>true, "title"=>"filter submissions by category", "description"=>"in addition to category, you can ensure the submission has a photo"}, "is:add"=>{"title"=>"add new submission", "encoding"=>"json", "href"=>"http://localhost:9292/submission_add_template/submit", "method"=>"POST", "template"=>{"title"=>"default title", "category"=>"cats", "photo_url"=>"http://cats.com"}}}, "submissions"=>[{"@controls"=>{"self"=>{"title"=>"submission 1", "href"=>"http://localhost:9292/view_submission/1"}}, "id"=>1, "category"=>"cats", "photo"=>"https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg"}, {"@controls"=>{"self"=>{"title"=>"submission 2", "href"=>"http://localhost:9292/view_submission/2"}}, "id"=>2, "category"=>"cats", "photo"=>"https://i.ytimg.com/vi/icqDxNab3Do/maxresdefault.jpg"}]})
|
17
|
-
end
|
18
|
-
|
19
|
-
get "/submission_filter_template/filter" do
|
20
|
-
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@controls"=>{"self"=>{"href"=>"http://localhost:9292/welcome/newest"}, "is:filter"=>{"href"=>"http://localhost:9292/submission_filter_template/filter?category={category}&has_photo={has_photo}", "isHrefTemplate"=>true, "title"=>"filter submissions by category", "description"=>"in addition to category, you can ensure the submission has a photo"}, "is:add"=>{"title"=>"add new submission", "encoding"=>"json", "href"=>"http://localhost:9292/submission_add_template/submit", "method"=>"POST", "template"=>{"title"=>"default title", "category"=>"cats", "photo_url"=>"http://cats.com"}}}, "submissions"=>[{"@controls"=>{"self"=>{"title"=>"submission 1", "href"=>"http://localhost:9292/view_submission/1"}}, "id"=>1, "category"=>"cats", "photo"=>"https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg"}, {"@controls"=>{"self"=>{"title"=>"submission 2", "href"=>"http://localhost:9292/view_submission/2"}}, "id"=>2, "category"=>"cats", "photo"=>"https://i.ytimg.com/vi/icqDxNab3Do/maxresdefault.jpg"}], "category"=>"#{params[:category]}", "has_photo"=>"#{params[:has_photo]}"})
|
21
|
-
end
|
22
|
-
|
23
|
-
post "/submission_add_template/submit" do
|
24
|
-
json({"@controls"=>{"self"=>{"title"=>"submission #{item_id}", "href"=>"http://localhost:9292/view_submission/#{item_id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/welcome/newest"}, "is:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "is:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"DELETE"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}", :message=>0})
|
25
|
-
end
|
26
|
-
|
27
|
-
get "/view_submission/newest" do
|
28
|
-
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@controls"=>{"self"=>{"title"=>"submission #{item_id}", "href"=>"http://localhost:9292/view_submission/#{item_id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/welcome/newest"}, "is:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "is:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"DELETE"}}, "submissions"=>[{"@controls"=>{"self"=>{"title"=>"submission 1", "href"=>"http://localhost:9292/view_submission/1"}}, "id"=>1, "category"=>"cats", "photo"=>"https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg"}, {"@controls"=>{"self"=>{"title"=>"submission 2", "href"=>"http://localhost:9292/view_submission/2"}}, "id"=>2, "category"=>"cats", "photo"=>"https://i.ytimg.com/vi/icqDxNab3Do/maxresdefault.jpg"}], "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"})
|
29
|
-
end
|
30
|
-
|
31
|
-
delete "/submission_delete_template/newest" do
|
32
|
-
json({"title"=>"View submissions", "description"=>"idk yet", "@meta"=>{"@title"=>"Submissions", "@description"=>"This resource represents submissions."}, "@controls"=>{"self"=>{"href"=>"http://localhost:9292/welcome/newest"}, "is:filter"=>{"href"=>"http://localhost:9292/submission_filter_template/filter?category={category}&has_photo={has_photo}", "isHrefTemplate"=>true, "title"=>"filter submissions by category", "description"=>"in addition to category, you can ensure the submission has a photo"}, "is:add"=>{"title"=>"add new submission", "encoding"=>"json", "href"=>"http://localhost:9292/submission_add_template/submit", "method"=>"POST", "template"=>{"title"=>"default title", "category"=>"cats", "photo_url"=>"http://cats.com"}}}, "submissions"=>[{"@controls"=>{"self"=>{"title"=>"submission 1", "href"=>"http://localhost:9292/view_submission/1"}}, "id"=>1, "category"=>"cats", "photo"=>"https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg"}, {"@controls"=>{"self"=>{"title"=>"submission 2", "href"=>"http://localhost:9292/view_submission/2"}}, "id"=>2, "category"=>"cats", "photo"=>"https://i.ytimg.com/vi/icqDxNab3Do/maxresdefault.jpg"}], :message=>0})
|
33
|
-
end
|
34
|
-
|
35
|
-
patch "/submission_edit_template/self" do
|
36
|
-
json({"@controls"=>{"self"=>{"title"=>"submission #{item_id}", "href"=>"http://localhost:9292/view_submission/#{item_id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/welcome/newest"}, "is:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "is:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"DELETE"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}", :message=>0})
|
37
|
-
end
|
38
|
-
|
39
|
-
|
40
|
-
get "/view_submission/:item_id" do
|
41
|
-
item_id = params[:item_id]
|
42
|
-
item = ViewSubmission.find(item_id)
|
43
|
-
json({"@controls"=>{"self"=>{"title"=>"submission #{item_id}", "href"=>"http://localhost:9292/view_submission/#{item_id}"}, "up"=>{"title"=>"View submissions", "href"=>"http://localhost:9292/welcome/newest"}, "is:edit"=>{"title"=>"update category or photo url", "encoding"=>"json", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"PATCH", "template"=>{"photo"=>"{new_url}", "category"=>"{new_category}"}}, "is:remove"=>{"title"=>"remove submission", "href"=>"http://localhost:9292/view_submission/#{item_id}", "method"=>"DELETE"}}, "id"=>"#{item.id}", "category"=>"#{item.category}", "photo"=>"#{item.photo}"})
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|