picatrix 0.5.0 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +17 -37
  4. data/Rakefile +35 -0
  5. data/bin/console +8 -4
  6. data/bin/post-receive.sh +3 -0
  7. data/bin/setup +7 -1
  8. data/generated/zoo.dot +37 -0
  9. data/generated/zoo.dot.png +0 -0
  10. data/{lib/picatrix/generated/view_submissions.rb → generated/zoo/resources/animals.rb} +10 -13
  11. data/generated/zoo/support/mason.rb +114 -0
  12. data/generated/zoo/support/namespaces.json +7 -0
  13. data/generated/zoo/support/picatrix.mason.pb.rb +95 -0
  14. data/generated/zoo/support/zoo.pb.rb +76 -0
  15. data/generated/zoo/support/zoo.proto +65 -0
  16. data/generated/zoo/zoo.rb +116 -0
  17. data/lib/picatrix.rb +25 -10
  18. data/lib/picatrix/buffy.rb +38 -40
  19. data/lib/picatrix/cruddy.rb +18 -16
  20. data/lib/picatrix/jenny.rb +31 -5
  21. data/lib/picatrix/link_relation_index.rb +1 -1
  22. data/lib/picatrix/pacman.rb +12 -6
  23. data/lib/picatrix/protoc.rb +7 -0
  24. data/lib/picatrix/prototyper.rb +56 -0
  25. data/lib/picatrix/routes.rb +40 -11
  26. data/{definitions/mason.proto → lib/picatrix/support/picatrix.mason.proto} +16 -13
  27. data/lib/picatrix/templates/app.proto +42 -0
  28. data/lib/picatrix/templates/app.rb +24 -136
  29. data/lib/picatrix/templates/mason.rb +114 -0
  30. data/lib/picatrix/templates/namespaces.json +7 -0
  31. data/lib/picatrix/templates/type.rb +6 -3
  32. data/lib/picatrix/transform_to_hash.rb +2 -2
  33. data/lib/picatrix/version.rb +1 -1
  34. data/notes.md +34 -0
  35. metadata +20 -10
  36. data/definitions/app.proto +0 -47
  37. data/lib/picatrix/fixtures/view_submission.rb +0 -19
  38. data/lib/picatrix/generated/app.pb.rb +0 -79
  39. data/lib/picatrix/generated/app.rb +0 -209
  40. data/lib/picatrix/generated/mason.pb.rb +0 -90
  41. data/lib/picatrix/generated/mason/namespaces.json +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28283e340d828d5a22f3152ccd81c502b863eccf
4
- data.tar.gz: d5c7a1a4234333f7002f3a6016c325a1fcd6f636
3
+ metadata.gz: cfdec538080a26d183c8338917e4906c48f12df3
4
+ data.tar.gz: 9795226f4ca351fda88a3caa0a9bd668e941f766
5
5
  SHA512:
6
- metadata.gz: c71a9ae39ddf75673c92affe67f2a93e5e61e81aef091596de7a037109ee301cf731439c67b4659cc8393d6de8b61f6910ddde9ba3639f11fbdfe4c36849e9c4
7
- data.tar.gz: 4f113d91d4e052728a87cdc347a902c732b2e3df02a33b150d2524fcb183b6a5caa1d6bd2e8d75afd97625a7a45d4594239389fa99822c8e80872195cf686b1d
6
+ metadata.gz: d6af26dcf377adbd88a4e7bbf057b0c367a1c4b4b90503f292a1c1f08295562fc9a6f48b3356d4ec10d4b6ba65e0cd2bd74fca7212f2725e60e3488c6df90552
7
+ data.tar.gz: 6a9cf7fd9b51d021800a8c726f96cc31c4d952b2741e1d01d76abaa9c30e20730a6574c3f305c5dfe58db644b20d64d0d60933ed83685a0828a4129bb641e656
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- picatrix (0.2.0)
4
+ picatrix (0.5.0)
5
5
  activesupport
6
6
  faker
7
7
  grape
data/README.md CHANGED
@@ -9,27 +9,21 @@
9
9
 
10
10
  An opinionated hypermedia API generator. :grin:
11
11
 
12
- ## Requires:
12
+ ## Requires
13
13
 
14
14
  - valid `.dot` file with [additional style guidelines](#dot-file-styles)
15
15
  - Protobuf [definitions of inputs/outputs](#protobuf-definitions-of-representations) for all state transitions, by node
16
16
 
17
17
 
18
- ## Outputs:
18
+ ## Outputs
19
19
 
20
20
  - basic Sinatra app and mock objects fitting your schema
21
- - protobuf generated representation objects (you dont edit these)
22
- - fixture interface to map to your persistance layer, is generated with fake data generators (you do edit these)
23
- - `application/vnd.mason+json`
24
- - controls
21
+ - intended to be a scaffold for your client to immediately test against, and maybe for you to build from or to (to as in match its interface in contract)
22
+ - `application/vnd.mason+json` hypermedia affordances
23
+ - CRUD + Filter actions are defined for you by default
24
+ - `$select` and `$expand` URL conventions apply
25
25
  - state diagram image ([see below](https://github.com/mooreniemi/picatrix#sample-image-output))
26
26
 
27
- ## About
28
-
29
- 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.
30
-
31
- 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.
32
-
33
27
  ## Installation
34
28
 
35
29
  Install system dependencies (Mac OS sample):
@@ -54,6 +48,8 @@ Or install it yourself as:
54
48
 
55
49
  ## getting ready
56
50
 
51
+ - easiest thing to do is use the rake task provided to make yourself a copy of the sample `dot` file which you can edit
52
+
57
53
  ### .dot file styles
58
54
 
59
55
  - edge style defaults to `arrowhead=odiamond` to signify default requests are `GET`
@@ -71,12 +67,15 @@ Or install it yourself as:
71
67
  - from the perspective of the client at any request, what does it need to make the request and have the server fufill its contract?
72
68
  - from the perspective of the server, what might the client want in response for it to make any interesting subsequent requests from this node in the workflow?
73
69
  - inputs will map onto controls, and outputs will map on to representations (dereferenced content)
74
- ## Usage
75
70
 
76
- In its final state, the intent is to use it as a CLI:
71
+ ## Usage
77
72
 
78
73
  ```bash
79
- $ bin/picapica dg_api.dot app_name
74
+ $ bin/picapica prep dg_api.dot app_name
75
+ => generated/app_name.proto
76
+ # at this point you flesh out your schema in your proto file
77
+ $ vi generated/app_name.proto
78
+ $ bin/picapica g dg_api.dot app_name
80
79
  => generated/app_name.rb
81
80
  ```
82
81
 
@@ -89,29 +88,10 @@ $ bin/picapica dg_api.dot app_name
89
88
 
90
89
  ### how to interpret the graph
91
90
 
92
- Nodes and edges translate roughly into application and/or resource states, and state transitions.
93
-
94
- 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.
95
-
96
- ## Development
97
-
98
- 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.
99
-
100
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
101
-
102
- ### TODO
103
-
104
- process goes: .dot file + `prep` (1)-> proto file from nodes + user input into .proto + `proto` (2)-> ruby representation classes + user input to fixturize (3)-> `g` (4)-> `rackup lib/picatrix/generated/app.rb`
105
-
106
- 1. outside in design process produced a diagram, which is written into a .dot file
107
- 2. all nodes are representations of resources, and thus get proto objects generated for them, here is where the inputs/outputs are formed into a schema
108
- 3. representation nodes now have ruby classes that reflect the information that will be sent back and forth in messages so we generate the app
109
- 4. boot up the app
110
-
111
- ## Contributing
112
-
113
- Bug reports and pull requests are welcome on [GitHub](https://github.com/mooreniemi/picatrix). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
91
+ Nodes and edges translate roughly into application and/or resource states, and state transitions. Labels on edges are link relations.
114
92
 
93
+ ## see also
94
+ [more notes](more-notes.md)
115
95
 
116
96
  ## License
117
97
 
data/Rakefile CHANGED
@@ -5,3 +5,38 @@ load 'protobuf/tasks/compile.rake'
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
 
7
7
  task :default => :spec
8
+
9
+ namespace :test do
10
+ desc "flesh out the proto file so you can generate from it"
11
+ task :setup do
12
+ puts "copying app.proto from spec/support/definitions/"
13
+ `cp spec/support/definitions/app.proto generated/app.proto`
14
+ end
15
+
16
+ desc "regen ruby from protobuf"
17
+ task :regen do
18
+ puts "regenerating ruby classes from mock definitions"
19
+ `protoc -I ./lib/picatrix/support -I ./generated --ruby_out ./generated/support generated/app.proto`
20
+ end
21
+
22
+ desc "serve example app (you may need to run test:setup first)"
23
+ task :serve do
24
+ `rackup generated/app.rb`
25
+ end
26
+
27
+ desc "generate new image of example graph"
28
+ task :png do
29
+ `dot -Tpng spec/support/dg_api.dot -o spec/support/dg_api.dot.png`
30
+ end
31
+ end
32
+
33
+ namespace :app do
34
+ desc "generate .dot file to work with"
35
+ task :dot, [:name] do |t, args|
36
+ `cp spec/support/dg_api.dot generated/#{args[:name]}.dot`
37
+ end
38
+ desc "serve your app by name"
39
+ task :serve, [:name] do |t, args|
40
+ `rackup generated/#{args[:name]}.rb`
41
+ end
42
+ end
data/bin/console CHANGED
@@ -1,13 +1,17 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "bundler/setup"
4
+
5
+ $LOAD_PATH.unshift File.expand_path('../../generated', __FILE__)
4
6
  require "picatrix"
5
7
 
6
- # generate ruby classes
7
- `protoc -I ./definitions --ruby_out ./lib/picatrix/generated definitions/*.proto`
8
+ puts "regen mason"
9
+ `protoc --ruby_out . lib/picatrix/support/picatrix.mason.proto`
10
+
11
+ puts "regen test app"
12
+ `protoc -I ./lib/picatrix/support -I ./generated --ruby_out ./generated generated/app.proto`
8
13
 
9
- require './lib/picatrix/generated/mason.pb.rb'
10
- require './lib/picatrix/generated/app.pb.rb'
14
+ require './generated/app.pb.rb'
11
15
 
12
16
  require "pry"
13
17
  Pry.start
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+ echo "ಠ╭╮ಠ"
3
+ git grep -i --color --break -n "TODO"
data/bin/setup CHANGED
@@ -2,6 +2,12 @@
2
2
  set -euo pipefail
3
3
  IFS=$'\n\t'
4
4
 
5
+ echo "installing graphviz"
6
+ brew install graphviz
7
+ echo "installing protobuf"
8
+ brew install protobuf
9
+ echo "installing bundler"
10
+ gem install bundler
11
+
5
12
  bundle install
6
13
 
7
- # Do any other automated setup that you need to do here
data/generated/zoo.dot ADDED
@@ -0,0 +1,37 @@
1
+ digraph d {
2
+ // means default method is GET
3
+ sep="+25,25";
4
+ overlap=scalexy;
5
+ nodesep=0.6;
6
+ splines=true;
7
+ graph [overlap = false];
8
+ edge [
9
+ arrowhead=odiamond
10
+ // this is just to make it more readable, set it to anything you want
11
+ fontcolor=blue
12
+ ]
13
+
14
+ // node definitions
15
+ // interpret shape=point as root
16
+ root [xlabel="inbound request" shape=point]
17
+ // shape=folder means collection
18
+ animals [label="View animals" shape=folder]
19
+ // shape=rectangle means item
20
+ animal [label="View animal" shape=rectangle]
21
+
22
+ // edge definitions
23
+ // source -> { target } [label="link relation name"]
24
+ root -> { animals } [label="newest"]
25
+ // style=dotted means inline representation
26
+ animals -> { animal } [label=":item_id"]
27
+ animals -> { animals } [label="filter"]
28
+ // style=bold && arrowhead=normal means POST
29
+ animals -> { animal } [label="create" style=bold arrowhead=normal]
30
+ // non-CRUD + Filter link relations will also be inflated
31
+ // animals -> { animals } [label="custom_relation" style=bold arrowhead=normal]
32
+ animal -> { animals } [label="newest"]
33
+ // color=red && fontcolor=red means DELETE
34
+ animals -> { animals } [label="newest" color=red fontcolor=red]
35
+ // arrowhead=normal means PATCH or PUT (if patch not supported)
36
+ animal -> { animal } [label="edit" arrowhead=normal]
37
+ }
Binary file
@@ -6,24 +6,18 @@ require 'faker'
6
6
  # technically, this is just an interface to it
7
7
  # so long as your persistance layer is able to implement
8
8
  # the methods in this fixture, the app will generate
9
- class ViewSubmissionsResource
9
+ class AnimalsResource
10
10
  # method used to return single item from a collection
11
11
  # creates an instance on the fly
12
12
  # both the find and collection methods use this
13
13
  def self.create(item_id)
14
- ViewSubmission.new(
14
+ Animal.new(
15
15
  {
16
16
  # any "bare" Proto type will be given an associated Faker
17
17
 
18
18
  :id => id = Faker::Number.number(6),
19
19
 
20
- :category => Faker::Lorem.word,
21
-
22
- :photo => Faker::Lorem.word,
23
-
24
- :controls => ViewSubmission::Controls.new(minimal_controls_for(item_id)),
25
-
26
- :attachments => [ViewSubmission::Attachment.new(params = {})],
20
+ :controls => Animal::Controls.new(minimal_controls_for(item_id)),
27
21
 
28
22
  }
29
23
  )
@@ -36,14 +30,17 @@ class ViewSubmissionsResource
36
30
  rand(10).times {
37
31
  collection << self.find(rand(1000))
38
32
  }
39
- ViewSubmissions.new(collection: collection)
33
+ Animals.new(collection: collection)
40
34
  end
41
-
35
+ def self.as_hashes
36
+ self.all.collection.map(&:to_hash)
37
+ end
38
+ # this makes no sense on this class
42
39
  def self.minimal_controls_for(item_id)
43
40
  host = "http://localhost:9292"
44
41
  {
45
- self: Mason::Self.new(href: "#{host}/view_submission/#{item_id}"),
46
- up: Mason::Up.new(href: "#{host}/view_submissions")
42
+ self: ::Picatrix::Mason::Self.new(href: "#{host}/animals/#{item_id}"),
43
+ up: ::Picatrix::Mason::Up.new(href: "#{host}/animals")
47
44
  }
48
45
  end
49
46
  end
@@ -0,0 +1,114 @@
1
+ module Picatrix
2
+ module Mason
3
+ def mason_up(type)
4
+ if type.to_s.pluralize == type
5
+ proc do |path, params|
6
+ {
7
+ up: Mason::Up.new(
8
+ {
9
+ href: "http://localhost:9292/#{}"
10
+ }
11
+ ).to_hash
12
+ }
13
+ end
14
+ else
15
+ proc do |path, params|
16
+ {
17
+ up: Mason::Up.new(
18
+ {
19
+ href: "http://localhost:9292/#{path.pluralize}"
20
+ }
21
+ ).to_hash
22
+ }
23
+ end
24
+ end
25
+ end
26
+ def mason_self(item)
27
+ proc do |path, params|
28
+ if params[:item_id]
29
+ {
30
+ self: Mason::Self.new(
31
+ {
32
+ href: "http://localhost:9292/#{path}/#{params[:item_id]}"
33
+ }
34
+ ).to_hash
35
+ }
36
+ else
37
+ {
38
+ self: Mason::Self.new(
39
+ {
40
+ href: "http://localhost:9292/#{path}"
41
+ }
42
+ ).to_hash
43
+ }
44
+ end
45
+ end
46
+ end
47
+ def edit(item)
48
+ proc do |path, params|
49
+ {
50
+ "z:edit": Mason::Edit.new(
51
+ {
52
+ href: "http://localhost:9292/#{path}/#{params[:item_id]}",
53
+ method: Mason::HTTPVerb::PATCH
54
+ }
55
+ ).to_hash
56
+ }
57
+ end
58
+ end
59
+ def remove(item)
60
+ proc do |path, params|
61
+ {
62
+ "z:remove": Mason::Remove.new(
63
+ {
64
+ href: "http://localhost:9292/#{path}/#{params[:item_id]}",
65
+ method: Mason::HTTPVerb::DELETE
66
+ }
67
+ ).to_hash
68
+ }
69
+ end
70
+ end
71
+ def create(collection)
72
+ proc do |path, params|
73
+ collection_name = collection.to_s.camelize
74
+ {
75
+ "z:create": Mason::Create.new(
76
+ {
77
+ href: "http://localhost:9292/#{path}",
78
+ method: Mason::HTTPVerb::POST,
79
+ title: "Create a new #{collection_name}",
80
+ create_template: "#{collection_name}CreateTemplate".constantize.new({})
81
+ }
82
+ )
83
+ }
84
+ end
85
+ end
86
+ def filter(collection)
87
+ proc do |path, params|
88
+ if params[:newest]
89
+ {
90
+ "z:filter": Mason::Filter.new(
91
+ {
92
+ href: "http://localhost:9292/#{path}?filter=newest",
93
+ isHrefTemplate: true,
94
+ method: Mason::HTTPVerb::GET,
95
+ title: "Show the newest additions to #{collection}"
96
+ }
97
+ ).to_hash
98
+ }
99
+ else
100
+ {
101
+ "z:filter": Mason::Filter.new(
102
+ {
103
+ href: "http://localhost:9292/#{path}?$select&{field1}={value1}&{field2}={value2}",
104
+ isHrefTemplate: true,
105
+ method: Mason::HTTPVerb::GET,
106
+ title: "Filter using $select on schema fields"
107
+ }
108
+ ).to_hash
109
+ }
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,7 @@
1
+ {
2
+ "@namespaces": {
3
+ "z": {
4
+ "name": "http://localhost:9292/rels#"
5
+ }
6
+ }
7
+ }
@@ -0,0 +1,95 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # This file is auto-generated. DO NOT EDIT!
5
+ #
6
+ require 'protobuf/message'
7
+
8
+ module Picatrix
9
+ module Mason
10
+
11
+ ##
12
+ # Enum Classes
13
+ #
14
+ class HTTPVerb < ::Protobuf::Enum
15
+ define :GET, 1
16
+ define :PUT, 2
17
+ define :PATCH, 3
18
+ define :DELETE, 4
19
+ define :POST, 5
20
+ end
21
+
22
+
23
+ ##
24
+ # Message Classes
25
+ #
26
+ class Self < ::Protobuf::Message; end
27
+ class Up < ::Protobuf::Message; end
28
+ class Filter < ::Protobuf::Message; end
29
+ class Create < ::Protobuf::Message; end
30
+ class Edit < ::Protobuf::Message; end
31
+ class Remove < ::Protobuf::Message; end
32
+ class Controls < ::Protobuf::Message; end
33
+
34
+
35
+ ##
36
+ # Message Fields
37
+ #
38
+ class Self
39
+ optional :string, :href, 1
40
+ optional :string, :title, 2
41
+ end
42
+
43
+ class Up
44
+ optional :string, :href, 1
45
+ optional :string, :title, 2
46
+ end
47
+
48
+ class Filter
49
+ optional :string, :href, 1
50
+ required ::Picatrix::Mason::HTTPVerb, :method, 2, :default => ::Picatrix::Mason::HTTPVerb::GET
51
+ required :bool, :isHrefTemplate, 3, :default => true
52
+ optional :string, :title, 4
53
+ # Extension Fields
54
+ extensions 10...20
55
+ end
56
+
57
+ class Create
58
+ optional :string, :href, 1
59
+ required ::Picatrix::Mason::HTTPVerb, :method, 2, :default => ::Picatrix::Mason::HTTPVerb::POST
60
+ optional :string, :title, 3
61
+ optional :string, :encoding, 4
62
+ # Extension Fields
63
+ extensions 10...20
64
+ end
65
+
66
+ class Edit
67
+ optional :string, :href, 1
68
+ required ::Picatrix::Mason::HTTPVerb, :method, 2, :default => ::Picatrix::Mason::HTTPVerb::PATCH
69
+ optional :string, :title, 3
70
+ optional :string, :encoding, 4
71
+ # Extension Fields
72
+ extensions 10...20
73
+ end
74
+
75
+ class Remove
76
+ optional :string, :href, 1
77
+ required ::Picatrix::Mason::HTTPVerb, :method, 2, :default => ::Picatrix::Mason::HTTPVerb::DELETE
78
+ optional :string, :title, 3
79
+ # Extension Fields
80
+ extensions 10...20
81
+ end
82
+
83
+ class Controls
84
+ optional ::Picatrix::Mason::Self, :self, 2
85
+ optional ::Picatrix::Mason::Up, :up, 3
86
+ optional ::Picatrix::Mason::Edit, :edit, 4
87
+ optional ::Picatrix::Mason::Remove, :remove, 5
88
+ optional ::Picatrix::Mason::Create, :create, 6
89
+ optional ::Picatrix::Mason::Filter, :filter, 7
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+