docrb-html 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +21 -0
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +52 -0
  5. data/Gemfile +7 -0
  6. data/Gemfile.lock +37 -0
  7. data/assets/breadcrumb.scss +25 -0
  8. data/assets/checkbox.scss +34 -0
  9. data/assets/class_header.scss +75 -0
  10. data/assets/class_mod_name.scss +8 -0
  11. data/assets/component_list.scss +4 -0
  12. data/assets/container.scss +9 -0
  13. data/assets/doc_box.scss +79 -0
  14. data/assets/documentation_block.scss +5 -0
  15. data/assets/favicon.ico +0 -0
  16. data/assets/fonts.scss +105 -0
  17. data/assets/footer.scss +15 -0
  18. data/assets/images/balance.svg +9 -0
  19. data/assets/images/breadcrumb_separator.svg +1 -0
  20. data/assets/images/checkbox-off.svg +1 -0
  21. data/assets/images/checkbox-on.svg +1 -0
  22. data/assets/images/chevron.svg +1 -0
  23. data/assets/images/docrb-label.svg +20 -0
  24. data/assets/images/github.svg +11 -0
  25. data/assets/images/home.svg +1 -0
  26. data/assets/images/inherited.svg +1 -0
  27. data/assets/images/override.svg +1 -0
  28. data/assets/images/questionmark.svg +1 -0
  29. data/assets/images/rubygems.svg +9 -0
  30. data/assets/images/user.svg +12 -0
  31. data/assets/js/filtering.js +66 -0
  32. data/assets/links.scss +16 -0
  33. data/assets/markdown.scss +41 -0
  34. data/assets/method_argument.scss +75 -0
  35. data/assets/method_display.scss +27 -0
  36. data/assets/method_list.scss +51 -0
  37. data/assets/project_header.scss +55 -0
  38. data/assets/reference.scss +36 -0
  39. data/assets/shared.scss +23 -0
  40. data/assets/style.scss +43 -0
  41. data/assets/symbol.scss +5 -0
  42. data/assets/tab_bar.scss +22 -0
  43. data/assets/text_block.scss +23 -0
  44. data/assets/type_definition.scss +3 -0
  45. data/assets/typedef.scss +6 -0
  46. data/bin/console +15 -0
  47. data/bin/setup +8 -0
  48. data/exe/docrb-html +12 -0
  49. data/lib/renderer/component/breadcrumb.rb +14 -0
  50. data/lib/renderer/component/checkbox.rb +9 -0
  51. data/lib/renderer/component/class_header.rb +14 -0
  52. data/lib/renderer/component/class_mod_name.rb +9 -0
  53. data/lib/renderer/component/component_list.rb +15 -0
  54. data/lib/renderer/component/doc_box.rb +38 -0
  55. data/lib/renderer/component/documentation_block.rb +9 -0
  56. data/lib/renderer/component/footer.rb +9 -0
  57. data/lib/renderer/component/markdown.rb +9 -0
  58. data/lib/renderer/component/method_argument.rb +106 -0
  59. data/lib/renderer/component/method_display.rb +9 -0
  60. data/lib/renderer/component/method_list.rb +9 -0
  61. data/lib/renderer/component/project_header.rb +9 -0
  62. data/lib/renderer/component/reference.rb +24 -0
  63. data/lib/renderer/component/symbol.rb +9 -0
  64. data/lib/renderer/component/tab_bar.rb +9 -0
  65. data/lib/renderer/component/text_block.rb +15 -0
  66. data/lib/renderer/component/type_definition.rb +9 -0
  67. data/lib/renderer/component/typedef.rb +9 -0
  68. data/lib/renderer/component.rb +50 -0
  69. data/lib/renderer/core_extensions.rb +11 -0
  70. data/lib/renderer/defs/specialized_object.rb +172 -0
  71. data/lib/renderer/defs/specialized_projection.rb +31 -0
  72. data/lib/renderer/defs.rb +180 -0
  73. data/lib/renderer/helpers.rb +82 -0
  74. data/lib/renderer/metadata.rb +44 -0
  75. data/lib/renderer/page.rb +17 -0
  76. data/lib/renderer/template.rb +38 -0
  77. data/lib/renderer/version.rb +5 -0
  78. data/lib/renderer.rb +129 -0
  79. data/renderer.gemspec +31 -0
  80. data/script/makecomponent +23 -0
  81. data/script/reload.js +14 -0
  82. data/script/serve +2 -0
  83. data/script/watch +17 -0
  84. data/templates/base.erb +25 -0
  85. data/templates/breadcrumb.erb +28 -0
  86. data/templates/checkbox.erb +8 -0
  87. data/templates/class_header.erb +53 -0
  88. data/templates/class_mod_name.erb +3 -0
  89. data/templates/component_list.erb +21 -0
  90. data/templates/doc_box.erb +82 -0
  91. data/templates/documentation_block.erb +18 -0
  92. data/templates/footer.erb +9 -0
  93. data/templates/markdown.erb +3 -0
  94. data/templates/method_argument.erb +29 -0
  95. data/templates/method_display.erb +28 -0
  96. data/templates/method_list.erb +25 -0
  97. data/templates/project_header.erb +38 -0
  98. data/templates/reference.erb +14 -0
  99. data/templates/symbol.erb +3 -0
  100. data/templates/tab_bar.erb +7 -0
  101. data/templates/text_block.erb +16 -0
  102. data/templates/type_definition.erb +4 -0
  103. data/templates/typedef.erb +3 -0
  104. metadata +178 -0
@@ -0,0 +1,66 @@
1
+ // ((document) => {
2
+ // document.addEventListener('DOMContentLoaded', () => {
3
+ const hideInternalCheck = document.querySelector("#filter-hide-internal");
4
+ const hidePrivateCheck = document.querySelector("#filter-hide-private");
5
+ const hideAttrsCheck = document.querySelector("#filter-hide-attrs");
6
+ const hideInheritedCheck = document.querySelector("#filter-hide-inherited");
7
+ const showExtendedCheck = document.querySelector("#filter-show-extended");
8
+ const showIncludedCheck = document.querySelector("#filter-show-included");
9
+
10
+ const allChecks = [
11
+ hideInternalCheck,
12
+ hidePrivateCheck,
13
+ hideAttrsCheck,
14
+ hideInheritedCheck,
15
+ showExtendedCheck,
16
+ showIncludedCheck,
17
+ ].filter(el => el);
18
+
19
+ const determineVisibility = () => ({
20
+ '[data-visibility="internal"]': !hideInternalCheck.checked,
21
+ '[data-visibility="private"]': !hidePrivateCheck.checked,
22
+ '[data-type="attribute"]': !hideAttrsCheck.checked,
23
+ '[data-origin="inheritance"]': !hideInheritedCheck.checked,
24
+ '[data-origin="inclusion"]': showIncludedCheck.checked,
25
+ '[data-origin="extension"]': showExtendedCheck.checked,
26
+ });
27
+ const attrs = ["data-visibility", "data-type", "data-origin"];
28
+ const filters = Object.keys(determineVisibility());
29
+
30
+ const applyVisibility = () => {
31
+ const opts = determineVisibility()
32
+ document
33
+ .querySelectorAll(attrs.map(i => `[${i}]`).join(","))
34
+ .forEach(el => {
35
+ const show = attrs
36
+ .map(k => el.attributes[k])
37
+ .filter(att => att)
38
+ .map(({name, value}) => opts[`[${name}="${value}"]`])
39
+ .filter(i => i !== undefined)
40
+ .reduce((a, b) => a && b, true);
41
+ el.style.display = show ? "" : "none";
42
+ });
43
+
44
+ document
45
+ .querySelectorAll("#attributes,#class-methods,#instance-methods")
46
+ .forEach(parent => {
47
+ const anyVisible = Array
48
+ .from(parent.querySelectorAll("[id]"))
49
+ .some(el => el.style.display != "none");
50
+
51
+ parent.style.display = anyVisible ? "" : "none";
52
+ document
53
+ .querySelectorAll(`a[href="#${parent.id}"]`)
54
+ .forEach(el => {
55
+ el.style.display = anyVisible ? "" : "none";
56
+ })
57
+ })
58
+ };
59
+
60
+ allChecks.forEach(el => {
61
+ el.addEventListener('change', () => applyVisibility());
62
+ });
63
+
64
+ applyVisibility();
65
+ // });
66
+ // })(document);
data/assets/links.scss ADDED
@@ -0,0 +1,16 @@
1
+ a {
2
+ @include body($weight: 500);
3
+ color: #FFFFFF;
4
+ cursor: pointer;
5
+ text-decoration: none;
6
+
7
+ &.dotted {
8
+ border-bottom: white 1px dotted;
9
+ padding-bottom: 3px;
10
+ }
11
+
12
+ &.dashed {
13
+ border-bottom: white 1px dashed;
14
+ padding-bottom: 3px;
15
+ }
16
+ }
@@ -0,0 +1,41 @@
1
+ div.markdown-base {
2
+ @include body;
3
+ color: #fff;
4
+ background-color: #1C1C1E;
5
+ padding: 12px 24px;
6
+
7
+ h1 {
8
+ border-bottom: 1px solid #373e47;
9
+ padding-bottom: 8px;
10
+ }
11
+
12
+ h1, h2, h3, h4, h5 {
13
+ margin: 12px 0;
14
+ }
15
+
16
+ p code {
17
+ background-color: #242426;
18
+ font-size: 80%;
19
+ padding: 3px 4px;
20
+ border-radius: 3px;
21
+ }
22
+
23
+ p {
24
+ margin-bottom: 8px;
25
+ line-height: 22px;
26
+ }
27
+
28
+ p + h1, p + h2, p + h3, p + h4, p + h5 {
29
+ margin-top: 24px;
30
+ }
31
+
32
+ a {
33
+ color: #fff;
34
+ border-bottom: dashed 1px white;
35
+ text-decoration: none;
36
+ }
37
+
38
+ code, pre {
39
+ @include mono($size: 15);
40
+ }
41
+ }
@@ -0,0 +1,75 @@
1
+ div.method-argument-base {
2
+ color: #FFAB42;
3
+ display: inline;
4
+ display: flex;
5
+
6
+ span { display: inline-block; }
7
+
8
+ &:not(:first-of-type) {
9
+ margin-left: 8px;
10
+ }
11
+
12
+ &:not(:last-of-type) {
13
+ &:after {
14
+ content: ',';
15
+ color: #A5ACBA;
16
+ }
17
+ }
18
+
19
+ .rest-arg {
20
+ color: #FF724C;
21
+ &.double {
22
+ &:after { content: "**" }
23
+ }
24
+ &.single {
25
+ &:after { content: "*" }
26
+ }
27
+ &.block {
28
+ &:after { content: "&" }
29
+ }
30
+ }
31
+
32
+ @mixin base_arg { margin-left: 8px; }
33
+
34
+ .continuation {
35
+ @include base_arg;
36
+ margin: 0;
37
+ &.equal {
38
+ color: #FF724C;
39
+ margin: 0 0 0 8px;
40
+ &:after {
41
+ content: "=";
42
+ }
43
+ }
44
+ &.colon {
45
+ color: #A5ACBA;
46
+
47
+ &:after {
48
+ content: ':';
49
+ }
50
+
51
+ &.double {
52
+ &:after {
53
+ content: '::';
54
+ }
55
+ }
56
+ }
57
+
58
+ + span {
59
+ margin-left: 8px;
60
+ }
61
+ }
62
+
63
+ .simple-argument {
64
+ &.symbol { color: #CF91C9; }
65
+ &.number { color: #FF724C; }
66
+ &.string {
67
+ color: #8CC98F;
68
+ :before, :after {
69
+ content: '"';
70
+ color: #39B6B5;
71
+ }
72
+ }
73
+ &.plain { color: white; }
74
+ }
75
+ }
@@ -0,0 +1,27 @@
1
+ div.method-display-base {
2
+ @include container;
3
+ margin-top: 8px;
4
+ .container {
5
+ @include container;
6
+ }
7
+
8
+ .method-name {
9
+ @include mono;
10
+ color: #39B6B5;
11
+ }
12
+
13
+ .argument-container {
14
+ @include mono;
15
+ color: #39B6B5;
16
+ display: flex;
17
+
18
+ &.not-empty {
19
+ &:before { content: '(' }
20
+ &:after { content: ')' }
21
+ }
22
+ }
23
+
24
+ .label {
25
+ @include label;
26
+ }
27
+ }
@@ -0,0 +1,51 @@
1
+ div.method-list-base {
2
+ .method-definition {
3
+ margin-bottom: 23px;
4
+ }
5
+
6
+ .doc-block {
7
+ margin-top: 8px;
8
+ }
9
+
10
+ .source-block {
11
+ margin: 13px 0 22px 0;
12
+ position: relative;
13
+ display: block;
14
+
15
+ &[open] {
16
+ summary {
17
+ .expanded { display: block }
18
+ .collapsed { display: none }
19
+ }
20
+ }
21
+
22
+ summary {
23
+ display: inline-block;
24
+ list-style: none;
25
+ > span {
26
+ @include body($weight: 500);
27
+ border-bottom: white 1px dotted;
28
+ cursor: pointer;
29
+ color: #FFF;
30
+ }
31
+
32
+ .expanded { display: none }
33
+ .collapsed { display: block }
34
+ }
35
+
36
+ .markdown-base > .highlight {
37
+ margin-bottom: 0;
38
+ }
39
+
40
+ .from {
41
+ @include body;
42
+ font-size: 80%;
43
+ color: white;
44
+ margin-bottom: 30px;
45
+ a {
46
+ font-size: inherit;
47
+ }
48
+ }
49
+ }
50
+
51
+ }
@@ -0,0 +1,55 @@
1
+ div.project-header-base {
2
+ padding-left: 52px;
3
+ padding-right: 40px;
4
+ background-color: #101010;
5
+ min-height: 240px;
6
+ display: flex;
7
+ justify-content: space-between;
8
+
9
+ .project {
10
+ @include body;
11
+ color: white;
12
+
13
+ h1 {
14
+ font-size: 64px;
15
+ font-weight: 300;
16
+ margin: 64px 0 0;
17
+ padding: 0;
18
+ }
19
+
20
+ h3 {
21
+ font-size: 16px;
22
+ font-weight: 400;
23
+ margin: 8px 0 0;
24
+ padding: 0;
25
+ }
26
+ }
27
+
28
+ .right {
29
+ display: flex;
30
+ align-items: center;
31
+ flex-direction: column;
32
+ color: white;
33
+ @include body;
34
+
35
+ .label {
36
+ display: inline-block;
37
+ }
38
+
39
+ .link-panel {
40
+ margin-top: 30px;
41
+ display: flex;
42
+ flex-direction: column;
43
+ align-items: flex-end;
44
+
45
+ .link-row {
46
+ display: flex;
47
+ margin-bottom: 6px;
48
+
49
+ svg {
50
+ margin-left: 8px;
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,36 @@
1
+ div.reference-base {
2
+ display: inline-flex;
3
+ cursor: pointer;
4
+ color: white;
5
+
6
+ .resolved {
7
+ border-color: white;
8
+ border-bottom: 1px dashed;
9
+
10
+ &.class { color: #FFAB42; border-color: #FFAB42; }
11
+ &.module { color: #579AD1; border-color: #579AD1; }
12
+ }
13
+
14
+ .unresolved {
15
+ border: 1px dotted #D8D8D8;
16
+ border-radius: 10px 3px 3px 10px;
17
+ display: inline-flex;
18
+ color: white;
19
+ justify-content: center;
20
+ align-content: center;
21
+ align-items: center;
22
+
23
+ .icon {
24
+ margin-left: 2px;
25
+ margin-right: 2px;
26
+ }
27
+
28
+ span {
29
+ @include mono($size: 15);
30
+ }
31
+ }
32
+
33
+ a {
34
+ @include mono($weight: 300, $size: 15);
35
+ }
36
+ }
@@ -0,0 +1,23 @@
1
+ .section-container {
2
+ margin: 25px 0 0;
3
+
4
+ .horizontal-container {
5
+ display: flex;
6
+ column-gap: 50px;
7
+
8
+ .child-structure {
9
+ .heading {
10
+ @include body($size: 24);
11
+ color: #FFFFFF;
12
+ padding-bottom: 12px;
13
+ }
14
+
15
+ .link-column {
16
+ display: flex;
17
+ flex-direction: column;
18
+ row-gap: 8px;
19
+ padding-left: 12px;
20
+ }
21
+ }
22
+ }
23
+ }
data/assets/style.scss ADDED
@@ -0,0 +1,43 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ padding: 0;
4
+ margin: 0;
5
+ }
6
+
7
+ html,
8
+ body {
9
+ max-width: 100vw;
10
+ overflow-x: hidden;
11
+ min-height: 100vh;
12
+ font-size: 15px;
13
+ justify-content: center;
14
+ line-height: 1.15;
15
+ -webkit-text-size-adjust: 100%;
16
+ text-rendering: geometricPrecision;
17
+ background-color: #1C1C1E;
18
+ }
19
+
20
+ @import "./fonts";
21
+ @import "./container";
22
+ @import "./shared";
23
+
24
+ @import "./links";
25
+ @import "./breadcrumb";
26
+ @import './footer';
27
+ @import './project_header';
28
+ @import './tab_bar';
29
+ @import './markdown';
30
+ @import './component_list';
31
+ @import './type_definition';
32
+ @import './class_mod_name';
33
+ @import './method_display';
34
+ @import './typedef';
35
+ @import './method_argument';
36
+ @import './class_header';
37
+ @import './checkbox';
38
+ @import './doc_box';
39
+ @import './documentation_block';
40
+ @import './text_block';
41
+ @import './reference';
42
+ @import './symbol';
43
+ @import './method_list';
@@ -0,0 +1,5 @@
1
+ div.symbol-base {
2
+ display: inline;
3
+ @include mono;
4
+ color: #CF91C9;
5
+ }
@@ -0,0 +1,22 @@
1
+ div.tab-bar-base {
2
+ height: 57px;
3
+ background: #161617;
4
+ padding: 12px 12px 0;
5
+ display: flex;
6
+
7
+ a {
8
+ padding: 12px 27px;
9
+ color: #FFFFFF;
10
+ border-radius: 3px 3px 0 0;
11
+ @include body;
12
+ cursor: pointer;
13
+
14
+ &.selected {
15
+ background-color: #1C1C1E;
16
+ }
17
+
18
+ &:hover:not(.selected) {
19
+ background-color: #18181A;
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,23 @@
1
+ div.text-block-base {
2
+ .html {
3
+ display: block;
4
+ &.inline {
5
+ display: inline;
6
+ }
7
+
8
+ margin-bottom: 12px;
9
+ &.no-margin {
10
+ margin-bottom: 0;
11
+ }
12
+
13
+ @include body;
14
+ color: #FFFFFF;
15
+ p code {
16
+ @include mono;
17
+ font-size: 95%;
18
+ padding: 3px 4px;
19
+ background-color: #29292B;
20
+ border-radius: 3px;
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,3 @@
1
+ div.type-definition-base {
2
+ @include container;
3
+ }
@@ -0,0 +1,6 @@
1
+ div.typedef-base {
2
+ @include mono($weight: 500);
3
+ color: #808080;
4
+ margin-right: 11px;
5
+ text-transform: capitalize;
6
+ }
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "renderer"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ 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
data/exe/docrb-html ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "renderer"
6
+
7
+ if ARGV.length != 2
8
+ puts "Usage: docrb-html INPUT OUTPUT"
9
+ exit 1
10
+ end
11
+
12
+ Renderer.new.render
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renderer
4
+ class Component
5
+ class Breadcrumb < Component
6
+ prop :project_name, :items
7
+
8
+ def prepare
9
+ @items ||= []
10
+ items.unshift({ name: "Components", parents: [] })
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renderer
4
+ class Component
5
+ class Checkbox < Component
6
+ prop :label, :checked
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renderer
4
+ class Component
5
+ class ClassHeader < Component
6
+ prop :type, :name, :definitions, :def_collection
7
+
8
+ def prepare
9
+ @definitions ||= []
10
+ @def_collection = @definitions.dup
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renderer
4
+ class Component
5
+ class ClassModName < Component
6
+ prop :href, :name
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renderer
4
+ class Component
5
+ class ComponentList < Component
6
+ prop :list, :parents, :class_name
7
+
8
+ def prepare
9
+ @list ||= []
10
+ @parents ||= []
11
+ nil
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renderer
4
+ class Component
5
+ class DocBox < Component
6
+ prop :item, :meta, :defs, :has_class_docs, :has_class_details, :has_attrs,
7
+ :has_class_methods, :has_instance_methods, :page_components,
8
+ :defs, :sdefs, :attrs
9
+
10
+ def prepare
11
+ @item = defs.specialized_projection.find_path(@item)
12
+
13
+ @has_class_docs = item[:doc] && !item[:doc].empty?
14
+ @defs = item.defs || []
15
+ @sdefs = item.sdefs || []
16
+ @attrs = item.attributes || []
17
+
18
+ @has_attrs = !@attrs.empty?
19
+ @has_class_methods = !@sdefs.empty?
20
+ @has_instance_methods = !@defs.empty?
21
+ @has_class_details =
22
+ !item[:inherits].nil? \
23
+ || !item.fetch(:extends, []).empty? \
24
+ || !item.fetch(:includes, []).empty? \
25
+ || !item.fetch(:modules, []).empty? \
26
+ || !item.fetch(:classes, []).empty?
27
+
28
+ @page_components = {
29
+ "class-documentation" => { enabled: has_class_docs, name: "Class Documentation" },
30
+ "class-details" => { enabled: has_class_details, name: "Inheritance" },
31
+ "attributes" => { enabled: has_attrs, name: "Attributes" },
32
+ "class-methods" => { enabled: has_class_methods, name: "Class Methods" },
33
+ "instance-methods" => { enabled: has_instance_methods, name: "Instance Methods" }
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renderer
4
+ class Component
5
+ class DocumentationBlock < Component
6
+ prop :doc, :class_name
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renderer
4
+ class Component
5
+ class Footer < Component
6
+ prop :updated_at, :version
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renderer
4
+ class Component
5
+ class Markdown < Component
6
+ prop :source
7
+ end
8
+ end
9
+ end