simple-hd-graph 0.1.0 → 0.3.3

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
  SHA256:
3
- metadata.gz: 44b324c969e0eee61a4e445debbb87b34d55a12995f1c72a4dc52d2f86807d68
4
- data.tar.gz: 3caefc54af9dadbcd83fc9dc5cd903f04a1acd9034043bf90424e83f888314ce
3
+ metadata.gz: 1ea0d42c32d8bd212ceaa306f4374b267c4f4158fdf9e9110e0c8f323ca6b729
4
+ data.tar.gz: cfad1721bc08d8a441093db14df1cff803520618d74c7a4087ab563d6878bfca
5
5
  SHA512:
6
- metadata.gz: 987f4cd19880122491628b747a516f38f4e1a3124cdd54ecbd200070b294a0227e7172ca6aa3c07cc21c455430ebe4c3b3ff7dad94e5566f7e784704ee501c5b
7
- data.tar.gz: c28ac4b38fdb99fa83e05b14992e935007ce0d7dfa760a87703fba4ad83e44b7ea1c289db222fcfcd2aac0f3b9a1c7de0961188b79d3d095f5f26e2a76989d6b
6
+ metadata.gz: 05ded502c1824bcccf27573c9a19135e176067b4db942999b4d53fc58b422043a9c339307bbb99f1af7ea91f91fac6ec1deb702b6d9221e04e47f2a4eae21bff
7
+ data.tar.gz: d48005f46fca5e2f5cf836c676fce9d2b43d4a4be2bc4af1e1bed8e06518daac7e1dd89e7146f861fca2d804ae286ef7486765e87e46aab41638d05867dc1f3f
data/.editorconfig ADDED
@@ -0,0 +1,3 @@
1
+ [*]
2
+ indent_size = 2
3
+ indent_style = space
data/README.md CHANGED
@@ -22,6 +22,101 @@ Or install it yourself as:
22
22
 
23
23
  $ simple-hd-graph -f FILE
24
24
 
25
+ or
26
+
27
+ $ simple-hd-graph -d DIR
28
+
29
+ ## Format
30
+
31
+ SimpleHdGraph was designed primarily to describe systems, its constituent resources, and their dependencies.
32
+
33
+ The two components are as follows:
34
+
35
+ * Context
36
+ * Resource
37
+
38
+ A single YAML document corresponds to a single context as below:
39
+
40
+ <pre>
41
+ <b>id</b>: name1
42
+ <b>resources</b>:
43
+ resource1:
44
+ note: memo
45
+ <b>has</b>: resource2
46
+ resource2:
47
+ note: very important
48
+ <b>depends</b>:
49
+ - name2
50
+ </pre>
51
+
52
+ features:
53
+
54
+ * Context can contain mutiple Resources
55
+ * Resource can use the `has` keyword to indicate that it owns other Resources
56
+ * Context can use the `depends` keyword to indicate its dependency on other Contexts
57
+
58
+ ## Example
59
+
60
+ input ( streams )
61
+
62
+ ```yaml
63
+ id: example1
64
+ resources:
65
+ web:
66
+ hosting: Heroku
67
+ runtime: Ruby 2.5
68
+ has:
69
+ - admin
70
+ - storage
71
+ admin:
72
+ hosting: Google Spreadsheet
73
+ runtime: Google Apps Script
74
+ storage:
75
+ hosting: AWS S3
76
+ region: ap-north-east1
77
+ ---
78
+ id: example 2
79
+ resources:
80
+ web:
81
+ hosting: Google AppEngines
82
+ runtime: Ruby 2.6
83
+ depends:
84
+ - example1
85
+ ```
86
+
87
+ output
88
+
89
+ ```plantuml
90
+ rectangle "example1" as example1 {
91
+ object "web" as example1Web {
92
+ hosting: Heroku
93
+ runtime: Ruby 2.5
94
+ }
95
+ object "admin" as example1Admin {
96
+ hosting: Google Spreadsheet
97
+ runtime: Google Apps Script
98
+ }
99
+ object "storage" as example1Storage {
100
+ hosting: AWS S3
101
+ region: ap-north-east1
102
+ }
103
+
104
+ example1Web -d-|> example1Admin
105
+ example1Web -d-|> example1Storage
106
+ }
107
+ rectangle "example 2" as example2 {
108
+ object "web" as example2Web {
109
+ hosting: Google AppEngines
110
+ runtime: Ruby 2.6
111
+ }
112
+ }
113
+ example2 -|> example1
114
+ ```
115
+
116
+ after plantuml converted
117
+
118
+ ![example output converted by plantuml](example.png)
119
+
25
120
  ## Development
26
121
 
27
122
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -30,4 +125,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
30
125
 
31
126
  ## Contributing
32
127
 
33
- Bug reports and pull requests are welcome on GitHub at https://github.com/wtnabe/graph.
128
+ Bug reports and pull requests are welcome on GitHub at https://github.com/wtnabe/simple-hd-graph.
data/example.png ADDED
Binary file
data/exe/simple-hd-graph CHANGED
@@ -1,9 +1,9 @@
1
1
  #! /usr/bin/env ruby
2
2
 
3
- $LOAD_PATH.unshift File.join(__dir__, '../lib')
4
- require 'bundler/setup'
3
+ $LOAD_PATH.unshift File.absolute_path(File.join(__dir__, '../lib'))
4
+
5
5
  require 'simple-hd-graph'
6
6
 
7
7
  Version = SimpleHdGraph::VERSION
8
- cmd = SimpleHdGraph::Command.new(ARGV)
9
- cmd.run
8
+ cmd = SimpleHdGraph::Command.new
9
+ cmd.run(ARGV)
@@ -4,5 +4,5 @@ module SimpleHdGraph
4
4
  end
5
5
 
6
6
  Dir.glob(__dir__ + '/simple-hd-graph/**/*.rb').each { |f|
7
- require_relative f.sub(/\.rb\z/, '')
7
+ require f.sub(/\.rb\z/, '')
8
8
  }
@@ -1,31 +1,83 @@
1
1
  require 'optparse'
2
2
 
3
3
  module SimpleHdGraph
4
+ class Error < StandardError; end
5
+ class FileNotExist < Error; end
6
+ class DirectoryNotExist < Error; end
7
+
4
8
  class Command
5
- def initialize(argv)
6
- @argv = argv.dup
9
+ #
10
+ # @param parser [Parser]
11
+ # @param reader [Reader]
12
+ # @param renderer [Symbol]
13
+ #
14
+ def initialize(parser: Parser.new, reader: Reader.new, renderer: :plantuml)
15
+ @parser = parser
16
+ @reader = reader
17
+ @renderer = SimpleHdGraph::Renderer.method(renderer.to_s)
7
18
  end
19
+ attr_reader :parser, :reader, :renderer
8
20
 
9
- def run
10
- opts.parse(@argv)
11
- if @file
12
- nodes = Parser.new.parse(Reader.new.read_file(@file))
13
- renderer = Renderer::PlantUML::Context.new
21
+ #
22
+ # @param argv [Array]
23
+ #
24
+ def run(argv)
25
+ parse(argv)
26
+ if @file || @dir
27
+ start
28
+ end
29
+ end
30
+
31
+ #
32
+ # @param argv [Array]
33
+ #
34
+ def parse(argv)
35
+ opts.parse(argv)
36
+ end
14
37
 
15
- puts nodes.map { |node|
16
- renderer.render(node)
17
- }.join
38
+ #
39
+ # @return [String]
40
+ #
41
+ def stream
42
+ if (@dir)
43
+ reader.read_dir(@dir)
44
+ else
45
+ reader.read_file(@file)
18
46
  end
19
47
  end
20
48
 
49
+ def start
50
+ nodes = parser.parse(stream)
51
+
52
+ @renderer.call(nodes)
53
+ end
54
+
21
55
  #
22
56
  # @return [OptionParser]
23
57
  #
24
- # :reek:NestedIterators
58
+ # :reek:NestedIterators, :reek:DuplicateMethodCall
25
59
  def opts
26
60
  OptionParser.new do |opt|
61
+ opt.on('-d DIR', '--dir', 'dirname') { |value|
62
+ if File.exist?(value) && File.directory?(value)
63
+ @dir = value
64
+ else
65
+ raise DirectoryNotExist, value
66
+ end
67
+ }
27
68
  opt.on('-f FILE', '--file', 'filename') { |value|
28
- @file = value
69
+ if File.exist?(value) && File.file?(value)
70
+ @file = value
71
+ else
72
+ raise FileNotExist, value
73
+ end
74
+ }
75
+ opt.on('-r RENDERER', '--renderer', 'renderer') { |value|
76
+ begin
77
+ @renderer = SimpleHdGraph::Renderer.method(value)
78
+ rescue NameError
79
+ STDERR.puts "[Warining] renderer `#{value}` not found. falling back to :plantuml"
80
+ end
29
81
  }
30
82
  end
31
83
  end
@@ -1,8 +1,10 @@
1
+ require 'simple-hd-graph/node'
2
+
1
3
  module SimpleHdGraph
2
4
  class ContextNode < Node
3
5
  required :id
4
6
 
5
- attr_reader :resources, :relations
7
+ attr_reader :resources, :relations, :depends # Array
6
8
 
7
9
  #
8
10
  # @return [String]
@@ -20,6 +22,9 @@ module SimpleHdGraph
20
22
  id
21
23
  end
22
24
 
25
+ #
26
+ # @param resource [ResourceNode]
27
+ #
23
28
  def <<(resource)
24
29
  @resources ||= []
25
30
  @resource_dict ||= {}
@@ -28,8 +33,15 @@ module SimpleHdGraph
28
33
  end
29
34
 
30
35
  #
31
- # :reek:NestedIterators
36
+ # @param depends [Array]
37
+ #
38
+ def set_depends(depends)
39
+ @depends = depends
40
+ end
41
+
42
+ # :reek:NestedIterators, :reek:TooManyStatements
32
43
  def refill_relation
44
+ @resource ||= []
33
45
  @relations ||= []
34
46
  @resources.each { |resource|
35
47
  dependencies = resource.has
@@ -13,6 +13,8 @@ module SimpleHdGraph
13
13
  end
14
14
  end
15
15
 
16
+ CAMELIZE_SEPARATOR = ' ,.、。'
17
+
16
18
  def initialize
17
19
  @inflector = Dry::Inflector.new
18
20
  end
@@ -24,7 +26,7 @@ module SimpleHdGraph
24
26
  def load(struct)
25
27
  klass = self.class
26
28
 
27
- required_fields = if klass.instance_variables.grep(':@required_fields').size > 0
29
+ required_fields = if klass.instance_variables.grep(/@required_fields/).size > 0
28
30
  klass.instance_variable_get('@required_fields')
29
31
  else
30
32
  nil
@@ -50,7 +52,7 @@ module SimpleHdGraph
50
52
  # @return [String]
51
53
  #
52
54
  def camelize(str)
53
- @inflector.camelize(@inflector.underscore(str.gsub(/ /, '_')))
55
+ @inflector.camelize(@inflector.underscore(str.gsub(/[#{CAMELIZE_SEPARATOR}]/, '_')))
54
56
  end
55
57
  end
56
58
  end
@@ -6,6 +6,10 @@ module SimpleHdGraph
6
6
  #
7
7
  # :reek:InstanceVaariableAssumption
8
8
  class Parser
9
+ KEYWORD_ID ||= 'id'.freeze
10
+ KEYWORD_RESOURCES ||= 'resources'.freeze
11
+ KEYWORD_DEPENDS ||= 'depends'.freeze
12
+
9
13
  #
10
14
  # @param document [String]
11
15
  #
@@ -14,30 +18,53 @@ module SimpleHdGraph
14
18
  contexts = []
15
19
 
16
20
  YAML.load_stream(document) do |node|
21
+ next unless node
22
+
17
23
  context = nil
18
- resources = []
24
+ resources = nil
25
+ depends = nil
19
26
 
20
- # :reek:NestedIterators
21
27
  node.each_pair { |key, value|
22
- if key == 'id'
28
+ case key
29
+ when KEYWORD_ID
23
30
  context = ContextNode.new
24
31
  context.load({ id: value })
25
- elsif reserved_keywords.include?(key)
26
- elsif key == 'resources'
32
+ when KEYWORD_DEPENDS
33
+ depends = value
34
+ when KEYWORD_RESOURCES
27
35
  resources = value
28
36
  end
29
37
  }
30
38
 
31
- resources.each { |key, resource|
32
- rn = ResourceNode.new
33
- rn.load_with_context({ id: context.id }, { key => resource })
34
- context << rn
35
- }
39
+ pack_depends_into_context(depends, context) if depends
40
+ pack_resources_into_context(resources, context) if resources
41
+
36
42
  contexts << context
37
43
  end
38
44
  refill_relation(contexts)
45
+ refill_depends(contexts)
46
+
47
+ contexts.map { |context| context.freeze }.freeze
48
+ end
49
+
50
+ #
51
+ # @param depends [Array]
52
+ # @param context [ContextNode]
53
+ #
54
+ def pack_depends_into_context(depends, context)
55
+ context.set_depends depends
56
+ end
39
57
 
40
- contexts
58
+ #
59
+ # @param resources [Array]
60
+ # @param context [ContextNode]
61
+ #
62
+ def pack_resources_into_context(resources, context)
63
+ resources.each { |key, resource|
64
+ rn = ResourceNode.new
65
+ rn.load_with_context({ id: context.id }, { key => resource })
66
+ context << rn
67
+ }
41
68
  end
42
69
 
43
70
  #
@@ -50,10 +77,19 @@ module SimpleHdGraph
50
77
  end
51
78
 
52
79
  #
53
- # @return [Array]
80
+ # @param context [Array]
54
81
  #
55
- def reserved_keywords
56
- [:depends]
82
+ def refill_depends(contexts)
83
+ contexts.map { |context|
84
+ if context.depends
85
+ regularized = context.depends.map { |dependee|
86
+ { context.id => contexts.select { |c| c.alias == dependee }.first.id }
87
+ }
88
+ context.set_depends regularized
89
+ else
90
+ context.set_depends []
91
+ end
92
+ }
57
93
  end
58
94
  end
59
95
  end
@@ -0,0 +1,16 @@
1
+ Dir.glob(File.join(__dir__, '**/*.rb')).each { |f| require f }
2
+
3
+ module SimpleHdGraph
4
+ module Renderer
5
+ #
6
+ # @param nodes [Array]
7
+ #
8
+ def plantuml(nodes)
9
+ context = self::PlantUML::Context.new
10
+ puts nodes.map { |node|
11
+ context.render(node)
12
+ }.join
13
+ end
14
+ module_function :plantuml
15
+ end
16
+ end
@@ -9,19 +9,23 @@ module SimpleHdGraph
9
9
  #
10
10
  # @param node [ContextNode]
11
11
  #
12
- # :reek:FeatureEnvy
12
+ # :reek:FeatureEnvy, :reek:DuplicateMethodCall
13
13
  def render(node)
14
14
  resources = node.resources.map { |resource|
15
15
  indent_resource(resource)
16
- }.join
16
+ }.join if node.resources.size > 0
17
17
  relations = node.relations.map { |relation|
18
18
  render_relation(relation)
19
- }.join("\n")
20
- <<EOD
19
+ }.join("\n") if node.relations.size > 0
20
+ depends = node.depends.map { |depending|
21
+ render_depends(depending)
22
+ }.join("\n") if node.depends.size > 0
23
+ (<<-EOD).gsub(/^$\n/, '')
21
24
  rectangle \"#{node.alias}\" as #{node.id} {
22
25
  #{resources}
23
- #{relations if relations.size > 0}
26
+ #{relations}
24
27
  }
28
+ #{depends}
25
29
  EOD
26
30
  end
27
31
 
@@ -44,6 +48,16 @@ EOD
44
48
  depender, dependee = relation.to_a.first
45
49
  " #{depender} -d-|> #{dependee}"
46
50
  end
51
+
52
+ #
53
+ # @param depending [Hash]
54
+ # @return [String]
55
+ #
56
+ # :reek:UtilityFunction
57
+ def render_depends(depending)
58
+ depender, dependee = depending.to_a.first
59
+ "#{depender} -|> #{dependee}"
60
+ end
47
61
  end
48
62
  end
49
63
  end
@@ -1,3 +1,5 @@
1
+ require 'simple-hd-graph/node'
2
+
1
3
  module SimpleHdGraph
2
4
  class ResourceNode < Node
3
5
  #
@@ -1,3 +1,3 @@
1
1
  module SimpleHdGraph
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-hd-graph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - wtnabe
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-15 00:00:00.000000000 Z
11
+ date: 2021-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-inflector
@@ -117,6 +117,7 @@ executables:
117
117
  extensions: []
118
118
  extra_rdoc_files: []
119
119
  files:
120
+ - ".editorconfig"
120
121
  - ".gitignore"
121
122
  - ".travis.yml"
122
123
  - Gemfile
@@ -125,6 +126,7 @@ files:
125
126
  - Rakefile
126
127
  - bin/console
127
128
  - bin/setup
129
+ - example.png
128
130
  - exe/simple-hd-graph
129
131
  - lib/simple-hd-graph.rb
130
132
  - lib/simple-hd-graph/command.rb
@@ -132,6 +134,7 @@ files:
132
134
  - lib/simple-hd-graph/node.rb
133
135
  - lib/simple-hd-graph/parser.rb
134
136
  - lib/simple-hd-graph/reader.rb
137
+ - lib/simple-hd-graph/renderer/plantuml.rb
135
138
  - lib/simple-hd-graph/renderer/plantuml/context.rb
136
139
  - lib/simple-hd-graph/renderer/plantuml/resource.rb
137
140
  - lib/simple-hd-graph/resource.rb