picatrix 0.2.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c1526c5c727bb983c60d9c3240984054c96187de
4
- data.tar.gz: 6af84973981466c805aa680fad9ca915353418f8
3
+ metadata.gz: 28283e340d828d5a22f3152ccd81c502b863eccf
4
+ data.tar.gz: d5c7a1a4234333f7002f3a6016c325a1fcd6f636
5
5
  SHA512:
6
- metadata.gz: b3feed7709d09d6b5bd06d3d88cc09de6a054bee63d24dd9cf62c01f80f356fbb0cdb20f6530c9b950f8c2fc8320273020ebeaae6892fbfc2ad7e51362c021d6
7
- data.tar.gz: 7f399c285ac1dde603ca580a3fdc2fe2fca415bc17dd24ef3a75f4ea2cfe5cd5b31c56175edc1840817349fc41c51e4ebce3ddbd16559ba09d340a3360ee7b94
6
+ metadata.gz: c71a9ae39ddf75673c92affe67f2a93e5e61e81aef091596de7a037109ee301cf731439c67b4659cc8393d6de8b61f6910ddde9ba3639f11fbdfe4c36849e9c4
7
+ data.tar.gz: 4f113d91d4e052728a87cdc347a902c732b2e3df02a33b150d2524fcb183b6a5caa1d6bd2e8d75afd97625a7a45d4594239389fa99822c8e80872195cf686b1d
data/Gemfile.lock CHANGED
@@ -1,11 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- picatrix (0.1.0)
4
+ picatrix (0.2.0)
5
5
  activesupport
6
+ faker
6
7
  grape
7
8
  grape-roar
8
9
  parslet
10
+ protobuf
9
11
  require_all
10
12
  roar
11
13
  ruby-graphviz
@@ -16,7 +18,7 @@ PATH
16
18
  GEM
17
19
  remote: https://rubygems.org/
18
20
  specs:
19
- activesupport (4.2.4)
21
+ activesupport (4.2.5)
20
22
  i18n (~> 0.7)
21
23
  json (~> 1.7, >= 1.7.7)
22
24
  minitest (~> 5.1)
@@ -36,6 +38,8 @@ GEM
36
38
  thread_safe (~> 0.3, >= 0.3.1)
37
39
  diff-lcs (1.2.5)
38
40
  equalizer (0.0.11)
41
+ faker (1.5.0)
42
+ i18n (~> 0.5)
39
43
  grape (0.13.0)
40
44
  activesupport
41
45
  builder
@@ -54,11 +58,17 @@ GEM
54
58
  ice_nine (0.11.1)
55
59
  json (1.8.3)
56
60
  method_source (0.8.2)
61
+ middleware (0.1.0)
57
62
  minitest (5.8.2)
58
63
  multi_json (1.11.2)
59
64
  multi_xml (0.5.5)
60
65
  parslet (1.7.1)
61
66
  blankslate (>= 2.0, <= 4.0)
67
+ protobuf (3.5.5)
68
+ activesupport (>= 3.2)
69
+ middleware
70
+ thor
71
+ thread_safe
62
72
  pry (0.10.3)
63
73
  coderay (~> 1.1.0)
64
74
  method_source (~> 0.8.1)
data/README.md CHANGED
@@ -5,27 +5,23 @@
5
5
  '. (___.'_/
6
6
  ((-((-''mrf
7
7
 
8
- # Picatrix
8
+ # picatrix
9
9
 
10
- An opinionated hypermedia API generator.
10
+ An opinionated hypermedia API generator. :grin:
11
11
 
12
- Requires:
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`
12
+ ## Requires:
13
+
14
+ - valid `.dot` file with [additional style guidelines](#dot-file-styles)
15
+ - Protobuf [definitions of inputs/outputs](#protobuf-definitions-of-representations) for all state transitions, by node
23
16
 
24
- Outputs:
25
- - Sinatra style routes
26
- - `application/vnd.mason+json` assets
27
- - serializers
28
- - templates (think forms, not views)
17
+
18
+ ## Outputs:
19
+
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
29
25
  - state diagram image ([see below](https://github.com/mooreniemi/picatrix#sample-image-output))
30
26
 
31
27
  ## About
@@ -36,6 +32,12 @@ The ideal way to use Picatrix is to do an exercise in designing your API "outsid
36
32
 
37
33
  ## Installation
38
34
 
35
+ Install system dependencies (Mac OS sample):
36
+
37
+ ```bash
38
+ $ brew install graphviz
39
+ $ brew install protobuf
40
+ ```
39
41
  Add this line to your application's Gemfile:
40
42
 
41
43
  ```ruby
@@ -50,6 +52,25 @@ Or install it yourself as:
50
52
 
51
53
  $ gem install picatrix
52
54
 
55
+ ## getting ready
56
+
57
+ ### .dot file styles
58
+
59
+ - edge style defaults to `arrowhead=odiamond` to signify default requests are `GET`
60
+ - the first node listed should be the root, and is signified by `xlabel=` and `shape=point`, you should never need to change this (unless you are knitting together workflows - future thing)
61
+ - collection nodes should be given `shape=folder` and pluralized
62
+ - the item node belonging to the collection node should be its singularized version and `shape=rectangle`
63
+ - `style=bold` and `arrowhead=normal` means `POST`
64
+ - `arrowhead=normal` alone means `PATCH`
65
+ - `color=red fontcolor=red` means `DELETE`
66
+
67
+ ### protobuf definitions of representations
68
+
69
+ - must match the node names (each node signifies a representation)
70
+ - consider
71
+ - 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
+ - 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
+ - inputs will map onto controls, and outputs will map on to representations (dereferenced content)
53
74
  ## Usage
54
75
 
55
76
  In its final state, the intent is to use it as a CLI:
@@ -70,8 +91,6 @@ $ bin/picapica dg_api.dot app_name
70
91
 
71
92
  Nodes and edges translate roughly into application and/or resource states, and state transitions.
72
93
 
73
- Dotted lines represent inlined relations. So, `View submissions` inlines `View submission` by `:item_id` (in this example a number).
74
-
75
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.
76
95
 
77
96
  ## Development
@@ -81,16 +100,13 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
81
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).
82
101
 
83
102
  ### TODO
84
- - generate sinatra routes from app & resource edges
85
- - initially make mason stubs myself
86
- - usage will be to iteratively make the necessary templates until routes are filled out
87
- - with all mason stubs established, make generators for them from
88
- - RAML?
89
- - json
90
- - yml?
91
-
92
- #### done
93
- - parse dot file in Ruby
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
94
110
 
95
111
  ## Contributing
96
112
 
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
+ load 'protobuf/tasks/compile.rake'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
5
6
 
data/bin/console CHANGED
@@ -3,5 +3,11 @@
3
3
  require "bundler/setup"
4
4
  require "picatrix"
5
5
 
6
+ # generate ruby classes
7
+ `protoc -I ./definitions --ruby_out ./lib/picatrix/generated definitions/*.proto`
8
+
9
+ require './lib/picatrix/generated/mason.pb.rb'
10
+ require './lib/picatrix/generated/app.pb.rb'
11
+
6
12
  require "pry"
7
- pry.start
13
+ Pry.start
@@ -0,0 +1,47 @@
1
+ import "mason.proto";
2
+
3
+ // objects
4
+ message ViewSubmission {
5
+ optional int32 id = 1;
6
+ optional string category = 2;
7
+ optional string photo = 3;
8
+
9
+ // items probably want a minimal representation
10
+ // of available controls when in collection view
11
+ message Controls {
12
+ optional mason.Self self = 2;
13
+ }
14
+
15
+ message Attachment {
16
+ optional int32 id = 1;
17
+ }
18
+
19
+ optional Controls controls = 4;
20
+ repeated Attachment attachments = 5;
21
+ }
22
+
23
+ message ViewSubmissions {
24
+ repeated ViewSubmission collection = 1;
25
+ }
26
+
27
+ // controls
28
+ message EditViewSubmission {
29
+ // someday gen this from schema?
30
+ optional mason.Edit form = 3;
31
+ message Template {
32
+ optional string category = 1;
33
+ optional string has_photo = 2;
34
+ }
35
+ optional Template template = 4;
36
+ }
37
+
38
+ message CreateViewSubmission {
39
+ // someday gen this from schema?
40
+ optional mason.Create form = 3;
41
+ message Template {
42
+ optional string category = 1;
43
+ optional string has_photo = 2;
44
+ }
45
+ optional Template template = 4;
46
+ }
47
+
@@ -0,0 +1,63 @@
1
+ package mason;
2
+
3
+ enum HTTPVerb {
4
+ GET = 1;
5
+ PUT = 2;
6
+ PATCH = 3;
7
+ DELETE = 4;
8
+ POST = 5;
9
+ }
10
+
11
+ message Self {
12
+ optional string href = 1;
13
+ optional string title = 2;
14
+ }
15
+
16
+ message Up {
17
+ optional string href = 1;
18
+ optional string title = 2;
19
+ }
20
+
21
+ // Filter should be broken out into custom Picatrix stuff
22
+ // as it's not really part of the Mason spec
23
+ message Filter {
24
+ enum HrefTemplate {
25
+ TRUE = 0;
26
+ FALSE = 1;
27
+ }
28
+
29
+ optional string href = 1;
30
+ optional HTTPVerb method = 2 [default = GET];
31
+ optional HrefTemplate isHrefTemplate = 3 [default = TRUE];
32
+ }
33
+
34
+ message Create {
35
+ optional string href = 1;
36
+ optional HTTPVerb method = 2 [default = POST];
37
+ optional string title = 3;
38
+ optional string encoding = 4;
39
+ }
40
+
41
+ message Edit {
42
+ optional string href = 1;
43
+ optional HTTPVerb method = 2 [default = PATCH];
44
+ optional string title = 3;
45
+ optional string encoding = 4;
46
+ }
47
+
48
+ message Remove {
49
+ optional string href = 1;
50
+ optional HTTPVerb method = 2 [default = DELETE];
51
+ optional string title = 3;
52
+ }
53
+
54
+ // when viewing an item directly, you see
55
+ // all available controls for it
56
+ message Controls {
57
+ optional Self self = 2;
58
+ optional Up up = 3;
59
+ optional Edit edit = 4;
60
+ optional Remove remove = 5;
61
+ optional Create create = 6;
62
+ optional Filter filter = 7;
63
+ }
@@ -0,0 +1,56 @@
1
+ require 'protobuf'
2
+ require 'faker'
3
+
4
+ module Picatrix
5
+ class Buffy
6
+ include Thor::Base
7
+ include Thor::Actions
8
+
9
+ attr_accessor :destination_stack, :options,
10
+ :resources, :id
11
+
12
+ source_root File.dirname(__FILE__)
13
+
14
+ PROTOBUF_FIXTURES = {
15
+ Protobuf::Field::Int32Field => "Faker::Number.number(6)",
16
+ Protobuf::Field::StringField => "Faker::Lorem.word"
17
+ }
18
+
19
+ def initialize(nodes, options = {})
20
+ # thor related
21
+ @options = options
22
+ @destination_stack = [self.class.source_root]
23
+
24
+ @resources = nodes.keys.select {|n| n if n.pluralize == n}
25
+ resources.each do |resource|
26
+ @resource_name = resource.camelize
27
+ @fields = @resource_name.singularize.
28
+ constantize.fields.inject({}) do |memo, field|
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
48
+ end
49
+ template(
50
+ 'templates/type.rb',
51
+ File.join("generated/#{resource}.rb")
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,45 @@
1
+ module Picatrix
2
+ class Cruddy
3
+ attr_accessor :controls
4
+
5
+ def initialize(edges)
6
+ @controls = edges.inject({}) do |memo, edge|
7
+ source = edge.keys.first
8
+ target = edge[source][:target]
9
+
10
+ next memo if source.upcase == "ROOT"
11
+
12
+ memo[target] = appropriate_controls_for(target)
13
+ memo
14
+ end
15
+ end
16
+
17
+ private
18
+ def appropriate_controls_for(source)
19
+ #TODO unless these become more diff again, should combine
20
+ if source.pluralize == source # collection?
21
+ {
22
+ source => template_map(:collection)
23
+ }
24
+ else
25
+ {
26
+ source => template_map(:item)
27
+ }
28
+ end
29
+ end
30
+ def template_map(type)
31
+ {
32
+ item: {
33
+ get: :mason_self,
34
+ patch: :edit,
35
+ put: :edit,
36
+ delete: :remove
37
+ },
38
+ collection: {
39
+ post: :create,
40
+ get: :filter
41
+ }
42
+ }[type]
43
+ end
44
+ end
45
+ end
@@ -10,7 +10,14 @@ module Picatrix
10
10
  (newline.absent? >> any).repeat(1) >>
11
11
  newline
12
12
  end
13
+ rule(:graph_setting) do
14
+ indent >>
15
+ (str(";").absent? >> any).repeat(0) >>
16
+ str(";") >>
17
+ newline
18
+ end
13
19
  rule(:default_definitions) do
20
+ graph_setting.repeat(0) >>
14
21
  indent >>
15
22
  str("edge [") >>
16
23
  (str("]").absent? >> any).repeat(0) >>
@@ -0,0 +1,19 @@
1
+ class ViewSubmissionFixture
2
+ # real object has more properties
3
+ def self.attributes
4
+ {
5
+ category: random_category,
6
+ photo: random_photo,
7
+ secret_data: "that won't be shared",
8
+ pci_data: "really won't appear"
9
+ }
10
+ end
11
+
12
+ def self.random_category
13
+ %w{ cats }.sample
14
+ end
15
+
16
+ def self.random_photo
17
+ %w{ http://imgur.com/r/cats/myEqIZx }.sample
18
+ end
19
+ end
@@ -0,0 +1,79 @@
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_relative 'mason.pb.rb'
13
+
14
+
15
+ ##
16
+ # Message Classes
17
+ #
18
+ class ViewSubmission < ::Protobuf::Message
19
+ class Controls < ::Protobuf::Message; end
20
+ class Attachment < ::Protobuf::Message; end
21
+
22
+ end
23
+
24
+ class ViewSubmissions < ::Protobuf::Message; end
25
+ class EditViewSubmission < ::Protobuf::Message
26
+ class Template < ::Protobuf::Message; end
27
+
28
+ end
29
+
30
+ class CreateViewSubmission < ::Protobuf::Message
31
+ class Template < ::Protobuf::Message; end
32
+
33
+ end
34
+
35
+
36
+
37
+ ##
38
+ # Message Fields
39
+ #
40
+ class ViewSubmission
41
+ class Controls
42
+ optional ::Mason::Self, :self, 2
43
+ end
44
+
45
+ class Attachment
46
+ optional :int32, :id, 1
47
+ end
48
+
49
+ optional :int32, :id, 1
50
+ optional :string, :category, 2
51
+ optional :string, :photo, 3
52
+ optional ::ViewSubmission::Controls, :controls, 4
53
+ repeated ::ViewSubmission::Attachment, :attachments, 5
54
+ end
55
+
56
+ class ViewSubmissions
57
+ repeated ::ViewSubmission, :collection, 1
58
+ end
59
+
60
+ class EditViewSubmission
61
+ class Template
62
+ optional :string, :category, 1
63
+ optional :string, :has_photo, 2
64
+ end
65
+
66
+ optional ::Mason::Edit, :form, 3
67
+ optional ::EditViewSubmission::Template, :template, 4
68
+ end
69
+
70
+ class CreateViewSubmission
71
+ class Template
72
+ optional :string, :category, 1
73
+ optional :string, :has_photo, 2
74
+ end
75
+
76
+ optional ::Mason::Create, :form, 3
77
+ optional ::CreateViewSubmission::Template, :template, 4
78
+ end
79
+