simple-hd-graph 0.1.0 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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