jekyll-archimate 0.1.0

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 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: []