picatrix 0.5.0 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +17 -37
- data/Rakefile +35 -0
- data/bin/console +8 -4
- data/bin/post-receive.sh +3 -0
- data/bin/setup +7 -1
- data/generated/zoo.dot +37 -0
- data/generated/zoo.dot.png +0 -0
- data/{lib/picatrix/generated/view_submissions.rb → generated/zoo/resources/animals.rb} +10 -13
- data/generated/zoo/support/mason.rb +114 -0
- data/generated/zoo/support/namespaces.json +7 -0
- data/generated/zoo/support/picatrix.mason.pb.rb +95 -0
- data/generated/zoo/support/zoo.pb.rb +76 -0
- data/generated/zoo/support/zoo.proto +65 -0
- data/generated/zoo/zoo.rb +116 -0
- data/lib/picatrix.rb +25 -10
- data/lib/picatrix/buffy.rb +38 -40
- data/lib/picatrix/cruddy.rb +18 -16
- data/lib/picatrix/jenny.rb +31 -5
- data/lib/picatrix/link_relation_index.rb +1 -1
- data/lib/picatrix/pacman.rb +12 -6
- data/lib/picatrix/protoc.rb +7 -0
- data/lib/picatrix/prototyper.rb +56 -0
- data/lib/picatrix/routes.rb +40 -11
- data/{definitions/mason.proto → lib/picatrix/support/picatrix.mason.proto} +16 -13
- data/lib/picatrix/templates/app.proto +42 -0
- data/lib/picatrix/templates/app.rb +24 -136
- data/lib/picatrix/templates/mason.rb +114 -0
- data/lib/picatrix/templates/namespaces.json +7 -0
- data/lib/picatrix/templates/type.rb +6 -3
- data/lib/picatrix/transform_to_hash.rb +2 -2
- data/lib/picatrix/version.rb +1 -1
- data/notes.md +34 -0
- metadata +20 -10
- data/definitions/app.proto +0 -47
- data/lib/picatrix/fixtures/view_submission.rb +0 -19
- data/lib/picatrix/generated/app.pb.rb +0 -79
- data/lib/picatrix/generated/app.rb +0 -209
- data/lib/picatrix/generated/mason.pb.rb +0 -90
- data/lib/picatrix/generated/mason/namespaces.json +0 -7
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# This file is auto-generated. DO NOT EDIT!
|
5
|
+
#
|
6
|
+
require 'protobuf/message'
|
7
|
+
|
8
|
+
|
9
|
+
##
|
10
|
+
# Imports
|
11
|
+
#
|
12
|
+
require 'picatrix.mason.pb'
|
13
|
+
|
14
|
+
|
15
|
+
##
|
16
|
+
# Message Classes
|
17
|
+
#
|
18
|
+
class Animals < ::Protobuf::Message
|
19
|
+
class Controls < ::Protobuf::Message; end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class Animal < ::Protobuf::Message
|
24
|
+
class Controls < ::Protobuf::Message; end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
class AnimalEditTemplate < ::Protobuf::Message; end
|
29
|
+
class AnimalRemoveTemplate < ::Protobuf::Message; end
|
30
|
+
class AnimalsCreateTemplate < ::Protobuf::Message; end
|
31
|
+
class AnimalsFilterTemplate < ::Protobuf::Message; end
|
32
|
+
class NewestAnimals < ::Protobuf::Message; end
|
33
|
+
|
34
|
+
|
35
|
+
##
|
36
|
+
# Message Fields
|
37
|
+
#
|
38
|
+
class Animals
|
39
|
+
class Controls
|
40
|
+
optional ::Picatrix::Mason::Self, :self, 1
|
41
|
+
end
|
42
|
+
|
43
|
+
optional :int32, :id, 1
|
44
|
+
optional ::Animals::Controls, :controls, 2
|
45
|
+
repeated ::Animal, :collection, 3
|
46
|
+
end
|
47
|
+
|
48
|
+
class Animal
|
49
|
+
class Controls
|
50
|
+
optional ::Picatrix::Mason::Self, :self, 1
|
51
|
+
end
|
52
|
+
|
53
|
+
optional :int32, :id, 1
|
54
|
+
optional ::Animal::Controls, :controls, 2
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
##
|
59
|
+
# Extended Message Fields
|
60
|
+
#
|
61
|
+
class ::Picatrix::Mason::Edit < ::Protobuf::Message
|
62
|
+
optional ::AnimalEditTemplate, :edit_template, 10, :extension => true
|
63
|
+
end
|
64
|
+
|
65
|
+
class ::Picatrix::Mason::Remove < ::Protobuf::Message
|
66
|
+
optional ::AnimalRemoveTemplate, :remove_template, 10, :extension => true
|
67
|
+
end
|
68
|
+
|
69
|
+
class ::Picatrix::Mason::Create < ::Protobuf::Message
|
70
|
+
optional ::AnimalsCreateTemplate, :create_template, 10, :extension => true
|
71
|
+
end
|
72
|
+
|
73
|
+
class ::Picatrix::Mason::Filter < ::Protobuf::Message
|
74
|
+
optional ::AnimalsFilterTemplate, :filter_template, 10, :extension => true
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import "picatrix.mason.proto";
|
2
|
+
|
3
|
+
// representation objects
|
4
|
+
|
5
|
+
message Animals {
|
6
|
+
optional int32 id = 1;
|
7
|
+
|
8
|
+
message Controls {
|
9
|
+
optional picatrix.mason.Self self = 1;
|
10
|
+
}
|
11
|
+
|
12
|
+
optional Controls controls = 2;
|
13
|
+
|
14
|
+
repeated Animal collection = 3;
|
15
|
+
|
16
|
+
}
|
17
|
+
|
18
|
+
message Animal {
|
19
|
+
optional int32 id = 1;
|
20
|
+
|
21
|
+
message Controls {
|
22
|
+
optional picatrix.mason.Self self = 1;
|
23
|
+
}
|
24
|
+
|
25
|
+
optional Controls controls = 2;
|
26
|
+
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
// generic CRUFD controls to extend
|
31
|
+
// per item representation
|
32
|
+
|
33
|
+
message AnimalEditTemplate {
|
34
|
+
}
|
35
|
+
extend picatrix.mason.Edit {
|
36
|
+
optional AnimalEditTemplate edit_template = 10;
|
37
|
+
}
|
38
|
+
|
39
|
+
message AnimalRemoveTemplate {
|
40
|
+
}
|
41
|
+
extend picatrix.mason.Remove {
|
42
|
+
optional AnimalRemoveTemplate remove_template = 10;
|
43
|
+
}
|
44
|
+
|
45
|
+
|
46
|
+
// per collection representation
|
47
|
+
|
48
|
+
message AnimalsCreateTemplate {
|
49
|
+
}
|
50
|
+
extend picatrix.mason.Create {
|
51
|
+
optional AnimalsCreateTemplate create_template = 10;
|
52
|
+
}
|
53
|
+
|
54
|
+
message AnimalsFilterTemplate {
|
55
|
+
}
|
56
|
+
extend picatrix.mason.Filter {
|
57
|
+
optional AnimalsFilterTemplate filter_template = 10;
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
// totally custom controls
|
62
|
+
|
63
|
+
message NewestAnimals {
|
64
|
+
}
|
65
|
+
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'sinatra/json'
|
3
|
+
require 'protobuf'
|
4
|
+
require 'require_all'
|
5
|
+
|
6
|
+
$:.unshift(File.join(File.dirname(__FILE__)))
|
7
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'support'))
|
8
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'resources'))
|
9
|
+
|
10
|
+
require("./generated/zoo/support/picatrix.mason.pb")
|
11
|
+
require("./generated/zoo/support/mason")
|
12
|
+
require("./generated/zoo/support/zoo.pb")
|
13
|
+
require_all("generated/zoo/resources/*.rb")
|
14
|
+
|
15
|
+
class Zoo < Sinatra::Base
|
16
|
+
include Picatrix::Mason
|
17
|
+
|
18
|
+
set :public_folder => "public", :static => true
|
19
|
+
|
20
|
+
get '/rels' do
|
21
|
+
json({:@controls=>{:up=>"http://localhost:9292/", :self=>"http://localhost:9292/rels"}, :link_relations=>{:newest=>["root -(GET)-> animals", "animal -(GET)-> animals", "animals -(DELETE)-> animals"], :":item_id"=>["animals -(GET)-> animal"], :filter=>["animals -(GET)-> animals"], :create=>["animals -(POST)-> animal"], :edit=>["animal -(PATCH)-> animal"]}})
|
22
|
+
end
|
23
|
+
|
24
|
+
get '/' do
|
25
|
+
status, headers, body = call env.merge("PATH_INFO" => "/animals")
|
26
|
+
[status, headers, body]
|
27
|
+
end
|
28
|
+
|
29
|
+
def json(hash = {})
|
30
|
+
# anything set here will be sent in all responses
|
31
|
+
super({"@namespaces"=>{"z"=>{"name"=>"http://localhost:9292/rels#"}}}.merge!(hash))
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
get "/animals" do
|
36
|
+
|
37
|
+
response_body = {"animals" => AnimalsResource.as_hashes}
|
38
|
+
|
39
|
+
controls = {}
|
40
|
+
|
41
|
+
|
42
|
+
controls.merge!(send("create".to_sym, Animals).call("animals".pluralize, params))
|
43
|
+
|
44
|
+
controls.merge!(send("filter".to_sym, Animals).call("animals".pluralize, params))
|
45
|
+
|
46
|
+
controls.merge!(send("mason_self".to_sym, Animals).call("animals".pluralize, params))
|
47
|
+
|
48
|
+
controls.merge!(send("mason_up".to_sym, Animals).call("animals".pluralize, params))
|
49
|
+
|
50
|
+
|
51
|
+
json({
|
52
|
+
:@controls => controls
|
53
|
+
}.merge!(response_body))
|
54
|
+
end
|
55
|
+
|
56
|
+
get "/animals/:item_id" do
|
57
|
+
|
58
|
+
response_body = AnimalsResource.find(params[:item_id]).to_hash.except(:controls)
|
59
|
+
|
60
|
+
controls = {}
|
61
|
+
|
62
|
+
|
63
|
+
controls.merge!(send("edit".to_sym, Animal).call("animal".pluralize, params))
|
64
|
+
|
65
|
+
controls.merge!(send("remove".to_sym, Animal).call("animal".pluralize, params))
|
66
|
+
|
67
|
+
controls.merge!(send("mason_self".to_sym, Animal).call("animal".pluralize, params))
|
68
|
+
|
69
|
+
controls.merge!(send("mason_up".to_sym, Animal).call("animal".pluralize, params))
|
70
|
+
|
71
|
+
|
72
|
+
json({
|
73
|
+
:@controls => controls
|
74
|
+
}.merge!(response_body))
|
75
|
+
end
|
76
|
+
|
77
|
+
post "/animals" do
|
78
|
+
|
79
|
+
response_body = AnimalsResource.create(params[:item_id]).to_hash.except(:controls)
|
80
|
+
|
81
|
+
controls = {}
|
82
|
+
|
83
|
+
json({
|
84
|
+
:@controls => controls
|
85
|
+
}.merge!(response_body))
|
86
|
+
end
|
87
|
+
|
88
|
+
delete "/animals/:item_id" do
|
89
|
+
|
90
|
+
response_body = {"animals" => AnimalsResource.as_hashes}
|
91
|
+
|
92
|
+
controls = {}
|
93
|
+
|
94
|
+
json({
|
95
|
+
:@controls => controls
|
96
|
+
}.merge!(response_body))
|
97
|
+
end
|
98
|
+
|
99
|
+
patch "/animals/:item_id" do
|
100
|
+
|
101
|
+
response_body = AnimalsResource.find(params[:item_id]).to_hash.except(:controls)
|
102
|
+
|
103
|
+
controls = {}
|
104
|
+
|
105
|
+
|
106
|
+
controls.merge!(send("mason_self".to_sym, Animal).call("animal".pluralize, params))
|
107
|
+
|
108
|
+
controls.merge!(send("mason_up".to_sym, Animal).call("animal".pluralize, params))
|
109
|
+
|
110
|
+
|
111
|
+
json({
|
112
|
+
:@controls => controls
|
113
|
+
}.merge!(response_body))
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
data/lib/picatrix.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib/picatrix/generated', __FILE__)
|
2
|
+
|
1
3
|
require "picatrix/version"
|
2
4
|
require "protobuf"
|
3
5
|
require "parslet"
|
@@ -9,31 +11,39 @@ require "thor"
|
|
9
11
|
require "picatrix/pacman"
|
10
12
|
require "picatrix/digraph_parser"
|
11
13
|
require "picatrix/transform_to_hash"
|
14
|
+
require "picatrix/buffy"
|
12
15
|
require "picatrix/link_relation_index"
|
13
16
|
require "picatrix/routes"
|
17
|
+
require "picatrix/protoc"
|
14
18
|
require "picatrix/cruddy"
|
15
|
-
require "picatrix/
|
19
|
+
require "picatrix/prototyper"
|
16
20
|
require "picatrix/jenny"
|
17
21
|
|
18
22
|
module Picatrix
|
19
23
|
class CLI < Thor
|
20
|
-
desc "g <dot file name> <
|
24
|
+
desc "g <dot file name> <optional: app name>",
|
25
|
+
"generates Sinatra app, uses dot file name for app name if none given"
|
21
26
|
option :force, :type => :boolean
|
22
27
|
|
23
|
-
def g(dot_file_name,
|
28
|
+
def g(dot_file_name, app_name = nil)
|
29
|
+
app_name = File.basename(dot_file_name, ".dot") if app_name.nil?
|
30
|
+
|
24
31
|
puts "using: #{dot_file_name}"
|
25
|
-
puts "output: #{
|
32
|
+
puts "output: #{app_name}"
|
26
33
|
|
27
34
|
Jenny.new(
|
28
35
|
Pacman.new(
|
29
36
|
dot_file_name
|
30
|
-
)
|
31
|
-
options
|
37
|
+
),
|
38
|
+
options,
|
39
|
+
app_name
|
32
40
|
).just_do_it
|
33
41
|
end
|
34
42
|
|
35
|
-
desc "prep <dot file name>", "outputs an image and
|
36
|
-
def prep(dot_file_name)
|
43
|
+
desc "prep <dot file name> <app name>", "outputs an image and protobuf templates"
|
44
|
+
def prep(dot_file_name, app_name = nil)
|
45
|
+
app_name = File.basename(dot_file_name, ".dot") if app_name.nil?
|
46
|
+
|
37
47
|
GraphViz.parse(dot_file_name, :path => "/usr/local/bin").
|
38
48
|
output(:png => "#{dot_file_name}.png")
|
39
49
|
puts "output to #{dot_file_name}.png"
|
@@ -41,9 +51,14 @@ module Picatrix
|
|
41
51
|
Buffy.new(
|
42
52
|
Pacman.new(
|
43
53
|
dot_file_name
|
44
|
-
)
|
45
|
-
|
54
|
+
),
|
55
|
+
options,
|
56
|
+
app_name
|
57
|
+
).slay
|
58
|
+
|
46
59
|
puts "output to generated/"
|
60
|
+
puts "You will need to edit your #{app_name}.proto file to match your schema." +
|
61
|
+
" Then you can run `picapica g <app_name>` to generate your application."
|
47
62
|
end
|
48
63
|
end
|
49
64
|
end
|
data/lib/picatrix/buffy.rb
CHANGED
@@ -1,56 +1,54 @@
|
|
1
|
-
require 'protobuf'
|
2
|
-
require 'faker'
|
3
|
-
|
4
1
|
module Picatrix
|
5
2
|
class Buffy
|
6
3
|
include Thor::Base
|
7
4
|
include Thor::Actions
|
8
5
|
|
9
|
-
attr_accessor :
|
10
|
-
:
|
6
|
+
attr_accessor :resources, :link_relations, :representation_klasses,
|
7
|
+
:app_name
|
11
8
|
|
12
|
-
|
9
|
+
# must be disjoint due to nature of protobuf
|
10
|
+
ITEM_ACTIONS = %w{ Edit Remove }
|
11
|
+
COL_ACTIONS = %w{ Create Filter }
|
12
|
+
CRUFD = %w{ Create Edit Remove Filter }
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
Protobuf::Field::StringField => "Faker::Lorem.word"
|
17
|
-
}
|
14
|
+
argument :name
|
15
|
+
source_root File.dirname(__FILE__)
|
18
16
|
|
19
|
-
def initialize(
|
17
|
+
def initialize(pacman, options = {}, app_name = "app")
|
20
18
|
# thor related
|
21
19
|
@options = options
|
22
20
|
@destination_stack = [self.class.source_root]
|
21
|
+
@app_name = app_name
|
22
|
+
|
23
|
+
@representation_klasses = pacman.nodes.keys.map(&:camelize)
|
24
|
+
|
25
|
+
@item_representations = @representation_klasses.map(&:singularize).uniq
|
26
|
+
@col_representations = @representation_klasses.map(&:pluralize).uniq
|
27
|
+
@resources = @item_representations + @col_representations
|
23
28
|
|
24
|
-
@
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
field_value =
|
31
|
-
if PROTOBUF_FIXTURES[field.type_class]
|
32
|
-
# TODO this is too general need some way to signal
|
33
|
-
# primary key which is addressable
|
34
|
-
if field.name.to_s.include?("id")
|
35
|
-
"id = #{PROTOBUF_FIXTURES[field.type_class]}"
|
36
|
-
else
|
37
|
-
PROTOBUF_FIXTURES[field.type_class]
|
38
|
-
end
|
39
|
-
elsif field.type_class.to_s.demodulize == "Controls"
|
40
|
-
"#{field.type_class}.new(minimal_controls_for(item_id))"
|
41
|
-
else
|
42
|
-
# TODO recursively gen these relations
|
43
|
-
"[#{field.type_class}.new(params = {})]"
|
44
|
-
end
|
45
|
-
|
46
|
-
memo[field.name] = field_value
|
47
|
-
memo
|
29
|
+
@link_relations = pacman.edges.collect do |edge|
|
30
|
+
target = edge[edge.keys.first][:target]
|
31
|
+
link_relation = edge[edge.keys.first][:link_relation]
|
32
|
+
if link_relation[0] != ':' && !CRUFD.map(&:downcase).include?(link_relation)
|
33
|
+
"#{link_relation.camelize}" + "#{target.camelize}"
|
48
34
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
35
|
+
end.compact.uniq
|
36
|
+
end
|
37
|
+
|
38
|
+
def slay
|
39
|
+
# TODO need to make prefix setter
|
40
|
+
@prefix = app_name[0]
|
41
|
+
@host = "http://localhost:9292/"
|
42
|
+
|
43
|
+
template(
|
44
|
+
'templates/namespaces.json',
|
45
|
+
File.join("../../generated/#{app_name}/support/namespaces.json")
|
46
|
+
)
|
47
|
+
|
48
|
+
template(
|
49
|
+
'templates/app.proto',
|
50
|
+
File.join("../../generated/#{app_name}/support/#{app_name}.proto")
|
51
|
+
)
|
54
52
|
end
|
55
53
|
end
|
56
54
|
end
|
data/lib/picatrix/cruddy.rb
CHANGED
@@ -2,6 +2,9 @@ module Picatrix
|
|
2
2
|
class Cruddy
|
3
3
|
attr_accessor :controls
|
4
4
|
|
5
|
+
# iow if it is addressable it has a self
|
6
|
+
DEFAULT_CONTROLS = [:mason_self, :mason_up]
|
7
|
+
|
5
8
|
def initialize(edges)
|
6
9
|
@controls = edges.inject({}) do |memo, edge|
|
7
10
|
source = edge.keys.first
|
@@ -16,30 +19,29 @@ module Picatrix
|
|
16
19
|
|
17
20
|
private
|
18
21
|
def appropriate_controls_for(source)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
}
|
24
|
-
else
|
25
|
-
{
|
26
|
-
source => template_map(:item)
|
27
|
-
}
|
28
|
-
end
|
22
|
+
by_size = collection?(source) ? :collection : :item
|
23
|
+
{
|
24
|
+
source => template_map(by_size)
|
25
|
+
}
|
29
26
|
end
|
30
27
|
def template_map(type)
|
31
28
|
{
|
29
|
+
# what controls do you want to get back
|
30
|
+
# from a given method on a item/collection
|
32
31
|
item: {
|
33
|
-
get: :
|
34
|
-
patch:
|
35
|
-
put:
|
36
|
-
delete: :
|
32
|
+
get: [:edit, :remove] + DEFAULT_CONTROLS,
|
33
|
+
patch: DEFAULT_CONTROLS,
|
34
|
+
put: DEFAULT_CONTROLS,
|
35
|
+
delete: [:mason_up]
|
37
36
|
},
|
38
37
|
collection: {
|
39
|
-
|
40
|
-
|
38
|
+
get: [:create, :filter] + DEFAULT_CONTROLS,
|
39
|
+
post: [:mason_self]
|
41
40
|
}
|
42
41
|
}[type]
|
43
42
|
end
|
43
|
+
def collection?(source)
|
44
|
+
source.pluralize == source
|
45
|
+
end
|
44
46
|
end
|
45
47
|
end
|