jekyll-archimate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7de1d6c85efc793fd744046d96c7e9e6a8177303
4
+ data.tar.gz: df8a2d1db4fa72b1c4527d59fd6182b31c3fea11
5
+ SHA512:
6
+ metadata.gz: a553f35f25a97cf3e8c8b136da045a773a18286af7e50f2a5598a88c14fd1428988606febbd49c3721e40f592a639b7ee8eac2f210d48d7901bf6d1c8a01f51d
7
+ data.tar.gz: a4098311ecda926ac1f1badd5fd885bc8d52fd35b3b01ed72205ed79f76c3edc68718f356d60ad41fe510a0b00710cfb9dd5845a0ab37cff23951c4bf3942cb2
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.15.3
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in jekyll-archimate.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Jekyll::Archimate
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/jekyll/archimate`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'jekyll-archimate'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install jekyll-archimate
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ 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
+
31
+ 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).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/jekyll-archimate.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "jekyll/archimate"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "jekyll/archimate/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jekyll-archimate"
8
+ spec.version = Jekyll::Archimate::VERSION
9
+ spec.authors = ["Mark Morga"]
10
+ spec.email = ["markmorga@gmail.com"]
11
+
12
+ spec.summary = %q{Jekyll plugins to support documenting ArchiMate models.}
13
+ spec.description = %q{Produces SVG diagrams and a JSON index useful for
14
+ search from an ArchiMate model file.}
15
+ spec.homepage = "https://github.com/mmorga/jekyll-archimate"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_runtime_dependency "jekyll", "~> 3.0"
25
+ spec.add_runtime_dependency "archimate", ">= 1.1"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.15"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "minitest", "~> 5.0"
30
+ end
@@ -0,0 +1,4 @@
1
+ require "jekyll/archimate/version"
2
+ require "jekyll/archimate/archimate_cache"
3
+ require "jekyll/archimate/archimate_diagram_tag"
4
+ require "jekyll/archimate/archimate_hook"
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "archimate"
4
+
5
+ module Jekyll
6
+ module Archimate
7
+ module ArchimateCache
8
+ # load an archimate model from either...
9
+ # 1. Memory
10
+ # 2. Cached & Marshaled File
11
+ # 3. Archimate File
12
+ # Defaulting to the Archimate file if it is newer than either cached version
13
+ def load_model(file_path)
14
+ @@cache ||= {}
15
+ file_path.sub!(%r{^/}, "")
16
+ mod_time = File.mtime(file_path)
17
+
18
+ if @@cache.key?(file_path)
19
+ model_info = @@cache[file_path]
20
+ return model_info[:model] if model_info[:cache_time] >= mod_time
21
+ end
22
+
23
+ cache_file = marshal_cache_file(file_path)
24
+ if File.exist?(cache_file) && File.mtime(cache_file) >= mod_time
25
+ @@cache[file_path] = {
26
+ cache_time: File.mtime(cache_file),
27
+ model: File.open(cache_file, "rb") { |f| Marshal.load(f) }
28
+ }
29
+ return @@cache[file_path][:model]
30
+ end
31
+
32
+ model = ::Archimate.read(file_path)
33
+ File.open(cache_file, "wb") { |f| Marshal.dump(model, f) }
34
+ @@cache[file_path] = {
35
+ cache_time: File.mtime(cache_file),
36
+ model: model
37
+ }
38
+
39
+ model
40
+ end
41
+ module_function :load_model
42
+
43
+ def rel_path(file_path)
44
+ file_path.sub!(%r{^/}, "")
45
+ end
46
+
47
+ module_function :rel_path
48
+
49
+ def cache_stale?(file_path)
50
+ @@cache ||= {}
51
+ rel = rel_path(file_path)
52
+ mod_time = File.mtime(rel)
53
+ !@@cache.key?(rel) ||
54
+ @@cache[rel][:cache_time] < mod_time
55
+ end
56
+ module_function :cache_stale?
57
+
58
+ def marshal_cache_file(path)
59
+ file_path, file_name = File.split(path)
60
+ cache_path = File.join("_cache", file_path).split("/").inject("") do |cpath, rel_dir|
61
+ npath = cpath.empty? ? rel_dir : File.join(cpath, rel_dir)
62
+ Dir.mkdir(File.absolute_path(npath)) unless Dir.exist?(File.absolute_path(npath))
63
+ npath
64
+ end
65
+ File.join(cache_path, File.basename(file_name, ".archimate" + ".marshal"))
66
+ end
67
+ module_function :marshal_cache_file
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,44 @@
1
+ module Jekyll
2
+ module Archimate
3
+ # Insert a diagram from the ArchiMate model.
4
+ #
5
+ # @param id [String] id of the diagram in the ArchiMate model
6
+ # @param caption [String] caption for the diagram
7
+ #
8
+ # {% archimate_diagram id-4623784 Gumball Manufacturing Business Process %}
9
+ #
10
+ class ArchimateDiagramTag < ::Liquid::Tag
11
+ def initialize(tag_name, args_text, tokens)
12
+ super
13
+
14
+ args = args_text.strip.split(" ")
15
+ @diagram_id = args.shift.strip
16
+ @caption = args.join(" ")
17
+ end
18
+
19
+ def render(context)
20
+ baseurl = context.registers[:site].baseurl
21
+ # TODO: make the archimate_dir configurable in _config.yml and as an
22
+ # optional argument in the tag.
23
+ archimate_dir = [baseurl, "archimate", "svg"].join("/")
24
+ <<~END
25
+ <figure id="#{@diagram_id}">
26
+ <a href="#{baseurl}/archimate/svg/#{@diagram_id}.svg" alt="View Full Screen">
27
+ <span class="glyphicon glyphicon-fullscreen" style="float:right"></span>
28
+ </a>
29
+ <img src="#{baseurl}/archimate/svg/#{@diagram_id}.svg" class="img-responsive" alt="#{@caption}">
30
+ <figcaption>
31
+ #{@caption}
32
+ <br/>
33
+ <a href="#{baseurl}/archimate/index.html##{@diagram_id}">
34
+ <small>View in ArchiMate Model Repository</small>
35
+ </a>
36
+ </figcaption>
37
+ </figure>
38
+ END
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ Liquid::Template.register_tag("archimate_diagram", Jekyll::Archimate::ArchimateDiagramTag)
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+ require "archimate"
3
+
4
+ module Jekyll
5
+ module Archimate
6
+ # Removes all keys that have null or empty values
7
+ def self.hash_purge(hash)
8
+ hash.delete_if { |_, value| !value || value.empty? }
9
+ end
10
+
11
+ # Base class for ArchiMate Entities: Model, Diagram, Element, Relationship
12
+ class EntityBase
13
+ attr_reader :entity
14
+
15
+ def initialize(entity)
16
+ @entity = entity
17
+ end
18
+
19
+ def to_h
20
+ Archimate.hash_purge(attr_hash)
21
+ end
22
+
23
+ def attr_hash
24
+ {
25
+ id: entity.id,
26
+ name: entity.name,
27
+ documentation: entity.documentation.map(&:to_h),
28
+ properties: entity.properties.map(&:to_h)
29
+ }
30
+ end
31
+ end
32
+
33
+ # Represents the overall model
34
+ class ModelEntity < EntityBase
35
+ def attr_hash
36
+ super.merge(
37
+ type: "Model"
38
+ )
39
+ end
40
+ end
41
+
42
+ # Represents an ArchiMate Element
43
+ class ElementEntity < EntityBase
44
+ def attr_hash
45
+ super.merge(
46
+ type: "Element",
47
+ element_type: entity.type,
48
+ relationships: entity.relationships.map(&:id),
49
+ views: entity.diagrams.map(&:id)
50
+ )
51
+ end
52
+ end
53
+
54
+ # Represents an ArchiMate Relationship
55
+ class RelationshipEntity < EntityBase
56
+ def attr_hash
57
+ super.merge(
58
+ type: "Relationship",
59
+ relationship_type: entity.type,
60
+ source: entity.source,
61
+ target: entity.target,
62
+ views: entity.diagrams.map(&:id)
63
+ )
64
+ end
65
+ end
66
+
67
+ # Represents an ArchiMate Diagram
68
+ class DiagramEntity < EntityBase
69
+ def attr_hash
70
+ super.merge(
71
+ type: "Diagram",
72
+ path: "svg/#{entity.id}.svg",
73
+ viewpoint: entity.viewpoint,
74
+ elements: entity.elements.map(&:id),
75
+ relationships: entity.relationships.map(&:id),
76
+ views: []
77
+ )
78
+ end
79
+ end
80
+
81
+ # Represents an ArchiMate Organizing Folder
82
+ class Folder
83
+ attr_reader :folder
84
+
85
+ def initialize(folder)
86
+ @folder = folder
87
+ end
88
+
89
+ # This item check is necessary because some models seem to contain
90
+ # an item that is a string rather than an element of some sort.
91
+ def items
92
+ folder.items.map { |item| item.is_a?(String) ? item : item.id }
93
+ end
94
+
95
+ def to_h
96
+ Archimate.hash_purge(
97
+ id: folder.id,
98
+ name: folder.name,
99
+ folders: folder.organizations.map { |child| Folder.new(child).to_h },
100
+ diagrams: items
101
+ )
102
+ end
103
+ end
104
+
105
+ # This is the top level object used by the web Archimate Navigator
106
+ class UnifiedModel
107
+ attr_reader :model
108
+
109
+ def initialize(model)
110
+ @model = model
111
+ end
112
+
113
+ def to_h
114
+ {
115
+ entities: entities,
116
+ folders: folders
117
+ }
118
+ end
119
+
120
+ def elements
121
+ model.elements.map { |element| ElementEntity.new(element).to_h }
122
+ end
123
+
124
+ def relationships
125
+ model.relationships.map { |relationship| RelationshipEntity.new(relationship).to_h }
126
+ end
127
+
128
+ def diagrams
129
+ model.diagrams.map { |diagram| DiagramEntity.new(diagram).to_h }
130
+ end
131
+
132
+ def entities
133
+ [ModelEntity.new(model).to_h].concat(
134
+ elements).concat(
135
+ relationships).concat(
136
+ diagrams)
137
+ end
138
+
139
+ def folders
140
+ [Folder.new(model.organizations.last).to_h]
141
+ end
142
+ end
143
+
144
+ # Writes any object that can be hashified (with to_h) to a JSON file
145
+ class JsonFile
146
+ def initialize(filename)
147
+ @filename = filename
148
+ end
149
+
150
+ def write(obj)
151
+ File.open(@filename, "wb") do |file|
152
+ file.write(JSON.generate(obj.to_h))
153
+ end
154
+ end
155
+ end
156
+
157
+ # Persists an ArchiMate diagram to a file
158
+ class SvgFile
159
+ def initialize(filename)
160
+ @filename = filename
161
+ end
162
+
163
+ def write(diagram)
164
+ File.open(@filename, "wb") do |svg_file|
165
+ svg_file.write(Archimate::Svg::Diagram.new(diagram).to_svg)
166
+ end
167
+ end
168
+ end
169
+
170
+ # Configuration variables:
171
+ # clean: clean destination directories before rendering
172
+ # layout: layout to use for the archimate navigator
173
+ class ArchimateHook
174
+ attr_reader :clean_generated_dirs
175
+ attr_reader :site
176
+ attr_reader :model
177
+ attr_reader :archimate_file
178
+
179
+ def initialize(site, archimate_file)
180
+ @site = site
181
+ @archimate_file = archimate_file
182
+ @clean_generated_dirs = @site.config.fetch('clean', false)
183
+ @model = ArchimateCache.load_model(archimate_file.sub(site.source, ""))
184
+ end
185
+
186
+ def generate
187
+ export_svgs
188
+ export_unified_json
189
+ end
190
+
191
+ def export_unified_json
192
+ dest_file = File.join(File.dirname(archimate_file), 'index.json')
193
+ dest_mtime = File.exist?(dest_file) && File.mtime(dest_file)
194
+ return unless !dest_mtime || File.mtime(archimate_file) > dest_mtime
195
+ JsonFile.new(dest_file).write(UnifiedModel.new(model))
196
+ end
197
+
198
+ def svg_dest_dir
199
+ @svg_dest_dir ||= File.join(File.dirname(archimate_file), 'svg')
200
+ end
201
+
202
+ def svgs_need_export?
203
+ Dir.mkdir(svg_dest_dir) unless Dir.exist?(svg_dest_dir)
204
+ last_svg_mtime = Dir.glob(File.join(svg_dest_dir, "*.svg")).map { |svg_file| File.mtime(svg_file) }.max
205
+ !last_svg_mtime || File.mtime(archimate_file) > last_svg_mtime
206
+ end
207
+
208
+ def export_svgs
209
+ return unless svgs_need_export?
210
+ model.diagrams.each do |diagram|
211
+ SvgFile.new(File.join(svg_dest_dir, "#{diagram.id}.svg")).write(diagram)
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ Jekyll::Hooks.register :site, :after_init do |site|
219
+ Jekyll.logger.info "ArchiMate Generator..."
220
+ Dir.glob("#{site.source}/**/*.archimate").each do |archimate_file|
221
+ unless archimate_file.start_with?(site.dest) || archimate_file.sub(site.source, "").start_with?("/_")
222
+ Jekyll.logger.info " processing: #{archimate_file}"
223
+ Jekyll::Archimate::ArchimateHook.new(site, archimate_file).generate
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,5 @@
1
+ module Jekyll
2
+ module Archimate
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-archimate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mark Morga
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-10-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: archimate
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.15'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.15'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '5.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.0'
83
+ description: |-
84
+ Produces SVG diagrams and a JSON index useful for
85
+ search from an ArchiMate model file.
86
+ email:
87
+ - markmorga@gmail.com
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".gitignore"
93
+ - ".travis.yml"
94
+ - Gemfile
95
+ - README.md
96
+ - Rakefile
97
+ - bin/console
98
+ - bin/setup
99
+ - jekyll-archimate.gemspec
100
+ - lib/jekyll/archimate.rb
101
+ - lib/jekyll/archimate/archimate_cache.rb
102
+ - lib/jekyll/archimate/archimate_diagram_tag.rb
103
+ - lib/jekyll/archimate/archimate_hook.rb
104
+ - lib/jekyll/archimate/version.rb
105
+ homepage: https://github.com/mmorga/jekyll-archimate
106
+ licenses: []
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.6.13
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Jekyll plugins to support documenting ArchiMate models.
128
+ test_files: []