power_stencil 0.4.6 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +46 -25
- data/doc/entities.md +131 -121
- data/doc/example_use_cases.md +3 -0
- data/doc/faq.md +5 -3
- data/doc/templates.md +11 -7
- data/lib/power_stencil/command_processors/entity_helper.rb +9 -1
- data/lib/power_stencil/dsl/base.rb +0 -4
- data/lib/power_stencil/dsl/entities.rb +4 -0
- data/lib/power_stencil/version.rb +1 -1
- data/power_stencil.gemspec +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0422be311b723e5ba9d9f58e0884b73964359b96
|
4
|
+
data.tar.gz: 594d2a82611aef291f2dfcf9237282d1dcd4a0d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cba7ef3b6731db7b4e5957536c5a8bfe182c6c533f8750d6a65baf4ba408aed245d32c62421ac652cbe7266a5c21cf6739a1ea3bb2d2f44fd7e3067e9e314c4f
|
7
|
+
data.tar.gz: 100ec840751ddfdba4e47bcb99769c666d7256f9882667f0da94c12987c1d6245947992c44772fc1511d98d402d3d8b9268b249eda5c7abcad08730d3f98260e
|
data/README.md
CHANGED
@@ -13,6 +13,10 @@ PowerStencil
|
|
13
13
|
- [Creating a `PowerStencil` project](#creating-a-powerstencil-project)
|
14
14
|
- [`PowerStencil` project structure](#powerstencil-project-structure)
|
15
15
|
- [Getting started](#getting-started)
|
16
|
+
- [Entities](#entities)
|
17
|
+
- [Templates](#templates)
|
18
|
+
- [Builds](#builds)
|
19
|
+
- [Plugins](#plugins)
|
16
20
|
- [Project status](#project-status)
|
17
21
|
- [Contributing](#contributing)
|
18
22
|
- [License](#license)
|
@@ -36,30 +40,37 @@ It is a common pattern to introduce a database to manage shared configuration fo
|
|
36
40
|
|
37
41
|
A `PowerStencil` project is composed of a data repository and a pretty standard templating flow to generate whatever is needed by your project or organization and **with `PowerStencil` everything is maintained in a git repository**: data, templates, specific code **without sacrificing on data integrity and relational features**. No more config loss, no more change applied without a full lineage.
|
38
42
|
|
39
|
-
**:information_source: With `PowerStencil` data can either be managed as documents to edit (Yaml) or code !!**.
|
43
|
+
**:information_source: With `PowerStencil` data can either be managed as documents to edit (Yaml) or fully as code within a powerful shell !!**. Choose the method that fits the most to what you are doing.
|
40
44
|
|
41
45
|
The `PowerStencil` gem provides the `power_stencil` executable which is a pluggable CLI to:
|
42
46
|
|
43
|
-
- Manage
|
44
|
-
-
|
45
|
-
-
|
46
|
-
-
|
47
|
+
- Manage your project **relational-integrity-checked data** in a versioned, git diff friendly yet flexible format.
|
48
|
+
- Visualize your **data relations with graphviz**. Customize generated graphs easily.
|
49
|
+
- Easily **manage templates** to generate whatever your project/organization requires.
|
50
|
+
- Define builds that you can easily **embed in your CI/CD process** or use them standalone.
|
51
|
+
- Ensure **re-usability** with a versatile extension mechanism including plugins.
|
47
52
|
|
48
53
|
# Pfff, yet another templating engine...
|
49
54
|
|
50
|
-
**Actually `PowerStencil` is _not_ a templating engine
|
51
|
-
|
55
|
+
**Actually `PowerStencil` is _not_ a templating engine**. It uses already existing and proven templating engines.
|
56
|
+
|
57
|
+
Currently it uses [ERB], which is a pretty standard and very well known engine in the [Ruby] world and especially for people who already used the [Rails] framework. Virtually any templating engine existing in the Ruby ecosystem could be integrated in the `PowerStencil` framework next to [ERB]. This will probably be the case in a future release, at least to integrate the [Haml] templating engine in order to ease the generation of XML-like files, still you obviously already can do it with [ERB].
|
58
|
+
|
59
|
+
No, the real value of `PowerStencil` is in the development flow it proposes around this templating mechanism, for both development and/or operations teams, and most specifically in **the way you organize and trace the data which is the real asset**, and in the way you can easily extend it to fit the particular needs of a project or organization.
|
52
60
|
|
53
|
-
No, the real value of `PowerStencil` is not really in its templating capabilities even if very powerful, but in the development flow it proposes around this templating mechanism for both development and/or operations teams, in the way you organize and trace the data which is the real asset, and in the way you can easily extend it to fit the particular needs of a project or organization.
|
54
61
|
|
55
62
|
# Installation
|
56
63
|
|
57
|
-
You need a working install of the [Ruby] language (>= 2.
|
64
|
+
You need a working install of the [Ruby] language (>= 2.3).
|
58
65
|
|
59
66
|
You can install the `PowerStencil` gem by issuing the usual:
|
60
67
|
|
61
68
|
$ gem install power_stencil
|
62
69
|
|
70
|
+
If you want to create graphviz graphs, you probably may want to install it for your system. If you are using an _apt-based_ system like Ubuntu or Debian it may probably be as simple as:
|
71
|
+
|
72
|
+
$ sudo apt install graphviz
|
73
|
+
|
63
74
|
# Usage
|
64
75
|
|
65
76
|
## Help
|
@@ -144,38 +155,47 @@ The structure of a brand new `PowerStencil` project is the following:
|
|
144
155
|
│ └── README.md
|
145
156
|
└── versioned-config.yaml
|
146
157
|
```
|
147
|
-
New directories will appear once you start some [builds] or when you will define [templates], but this is the initial state.
|
148
158
|
|
149
|
-
|
159
|
+
Other directories will appear once you start working with the project, perform some [builds] or when you will define [templates], but this is the initial state.
|
150
160
|
|
151
|
-
|
161
|
+
Not all the files in this directory should be versioned, and this the reason why there is a preconfigured `.gitignore` at the root of the project. It is prefilled so that unless you want to specifically avoid a file to be versioned, you don't need to worry regarding `PowerStencil` project files. **By default everything that must be versioned actually is and everything that shouldn't isn't**.
|
152
162
|
|
153
|
-
|
163
|
+
The project has two distinct config files.
|
154
164
|
|
155
|
-
|
165
|
+
- Keep the official project config in the `.ps_project/versioned-config.yaml` which, as its name suggest, will be versioned.
|
166
|
+
- But any developer who wants to temporarily override some configuration should do it in the `.ps_project/personal-config.yaml`, which is not be versioned. The content defined in the latter overrides the content of the official one.
|
167
|
+
|
168
|
+
**This is a clean way for anyone who wants to test something to safely do it locally without the risk to pollute the central repo.**
|
169
|
+
|
170
|
+
There is the same mechanism between `.ps_project/entities` (where the project data is stored and which is versioned) and `.ps_project/user_entities` (where local data is stored and not versioned), but as opposed to the two aforementioned config files, you should not edit anything directly there but instead use the CLI or the shell. More information on how to manage entities [here][entities].
|
171
|
+
|
172
|
+
The `plugins` directory can optionally contain project specific plugins. Plugins are a great way to extend `PowerStencil` for the needs of a project or organization.
|
156
173
|
|
157
174
|
## Getting started
|
158
175
|
|
159
|
-
|
176
|
+
See the four following topics as a kind of tutorial on `PowerStencil`. You should read them in order, as each of them assumes you already read the previous one.
|
177
|
+
|
178
|
+
### Entities
|
160
179
|
|
161
|
-
|
180
|
+
The **core of the system** is the **[entity][entities]**, so you should start by having a look at what entities are, how they are easily managed using the `PowerStencil` CLI and shell.
|
162
181
|
|
163
|
-
|
182
|
+
### Templates
|
164
183
|
|
165
|
-
|
184
|
+
Then it is important to understand how to use entities within **[templates]**. Templates are the way to **generate whatever you need** (doc, code, descriptors, sites, whatever...) from the data that the entities represent.
|
166
185
|
|
167
|
-
|
186
|
+
### Builds
|
168
187
|
|
169
|
-
|
188
|
+
The mechanism that **combines entities and templates** is called a **[build][builds]**. A build is always attached to an entity (you build something). The result of a build is a set of files. Optionally an action can be triggered after the files are generated (could be as simple as calling a script that has been generated).
|
170
189
|
|
171
|
-
|
190
|
+
### Plugins
|
172
191
|
|
173
|
-
|
192
|
+
`PowerStencil` could stop there, and you would be able to do whatever you want, but there is a whole world beyond. **[Plugins]** provide a way to completely **extend `PowerStencil` and ease cross-projects share and re-usability**, further control relations between entities, implement complex post-build actions, add CLI sub-commands and options.
|
193
|
+
Plugins can be local to the project or coming in the form of standard Ruby Gems ! The icing on the cake...
|
174
194
|
|
175
|
-
|
195
|
+
<br>
|
196
|
+
<br>
|
176
197
|
|
177
|
-
|
178
|
-
- See some real world [example use cases].
|
198
|
+
And course, you may want to **read the [F.A.Q.]**
|
179
199
|
|
180
200
|
# Project status
|
181
201
|
|
@@ -216,3 +236,4 @@ Everyone interacting in the PowerStencil project’s codebases, issue trackers,
|
|
216
236
|
[ERB]: https://ruby-doc.org/stdlib-2.6.3/libdoc/erb/rdoc/ERB.html "Quick ERB description"
|
217
237
|
[Haml]: http://haml.info/ "The templating engine for XML-like documents"
|
218
238
|
[Ruby]: https://www.ruby-lang.org "The powerful Ruby language"
|
239
|
+
[Rails]: https://rubyonrails.org/ "The Ruby on Rails framework"
|
data/doc/entities.md
CHANGED
@@ -25,14 +25,16 @@ Entities
|
|
25
25
|
- [entity_type](#entity_type)
|
26
26
|
- [auto_named_entity_type](#auto_named_entity_type)
|
27
27
|
- [field](#field)
|
28
|
-
- [
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
- [
|
28
|
+
- [Integrity constraints](#integrity-constraints)
|
29
|
+
- [is_array](#is_array)
|
30
|
+
- [is_hash](#is_hash)
|
31
|
+
- [not_null](#not_null)
|
32
|
+
- [not_empty](#not_empty)
|
33
|
+
- [should_match](#should_match)
|
34
|
+
- [class_name](#class_name)
|
35
|
+
- [Relational constraints](#relational-constraints)
|
36
|
+
- [has_one](#has_one)
|
37
|
+
- [has_many](#has_many)
|
36
38
|
- [buildable and buildable_by](#buildable-and-buildable_by)
|
37
39
|
- [Module you could include in your entity types](#module-you-could-include-in-your-entity-types)
|
38
40
|
- [Adding functional code](#adding-functional-code)
|
@@ -612,116 +614,11 @@ PowerStencil DSL> e.fields['another_field']
|
|
612
614
|
- The `name` field that we already saw and which is mandatory.
|
613
615
|
- The `description` field which is optional, and which is pretty self-explanatory.
|
614
616
|
|
615
|
-
### has_one
|
616
617
|
|
617
|
-
|
618
|
-
|
619
|
-
```ruby
|
620
|
-
class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity
|
621
|
-
entity_type :custom_entity
|
622
|
-
|
623
|
-
has_one :custom_entity, name: :parent
|
624
|
-
end
|
625
|
-
```
|
618
|
+
### Integrity constraints
|
626
619
|
|
627
|
-
```ruby
|
628
|
-
PowerStencil DSL> e = new_custom_entity name: :test_entity
|
629
|
-
=> #<MyCustomEntity:47215552142260 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566478203.584915)'>
|
630
|
-
PowerStencil DSL> p = new_custom_entity name: :foo
|
631
|
-
=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>
|
632
|
-
PowerStencil DSL> e.parent = p
|
633
|
-
=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>
|
634
|
-
PowerStencil DSL> e.fields
|
635
|
-
=> {:name=>"test_entity", :parent=>#<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>}
|
636
|
-
PowerStencil DSL> p.save=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>
|
637
|
-
PowerStencil DSL> e.save
|
638
|
-
=> #<MyCustomEntity:47215552142260 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566478203.584915)'>
|
639
|
-
PowerStencil DSL> exit
|
640
|
-
```
|
641
|
-
|
642
|
-
Which translates at persistence level as:
|
643
|
-
|
644
|
-
```shell
|
645
|
-
$ power_stencil get custom_entity/test_entity --raw
|
646
|
-
--- !ruby/object:MyCustomEntity
|
647
|
-
:name: test_entity
|
648
|
-
:parent: !psref
|
649
|
-
type: :custom_entity
|
650
|
-
name: foo
|
651
|
-
```
|
652
|
-
Here we are referencing an entity of the same type, but of course you can reference any type of entity. Using `has_one` will enforce the type of data you reference. Let's try to mess-up:
|
653
|
-
|
654
|
-
```ruby
|
655
|
-
PowerStencil DSL> e.parent = :bar
|
656
|
-
=> :bar
|
657
|
-
PowerStencil DSL> e.fields
|
658
|
-
=> {:name=>"test_entity", :parent=>:bar}
|
659
|
-
PowerStencil DSL> e.valid?
|
660
|
-
=> false
|
661
|
-
PowerStencil DSL> e.valid? raise_error: true
|
662
|
-
UniverseCompiler::Error: Invalid entity '[:custom_entity, "test_entity"]' for fields parent !
|
663
|
-
from /opt/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/universe_compiler-0.2.7/lib/universe_compiler/utils/error_propagation.rb:10:in `false_or_raise'
|
664
|
-
PowerStencil DSL> e.save
|
665
|
-
UniverseCompiler::Error: Invalid entity '[:custom_entity, "test_entity"]' for fields parent !
|
666
|
-
from /opt/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/universe_compiler-0.2.7/lib/universe_compiler/utils/error_propagation.rb:10:in `false_or_raise'
|
667
|
-
```
|
668
|
-
So you see that if we try to set parent with something wrong, the accessor seems to accept, you can even see the `#fields` Hash updated. But as soon as you try to save to entity, or if you use the `#valid?` method, it complains about the type... Cool.
|
669
|
-
|
670
|
-
:information_source: The `name` property of the `has_one` directive is optional. If not present the field will be named from the entity_type referenced instead...
|
671
620
|
|
672
|
-
|
673
|
-
|
674
|
-
### has_many
|
675
|
-
|
676
|
-
Once you know the `has_one` directive, you should not be surprised by the `has_many` directive...
|
677
|
-
|
678
|
-
```ruby
|
679
|
-
class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity
|
680
|
-
entity_type :custom_entity
|
681
|
-
|
682
|
-
has_many :base_entity, name: :sub_properties
|
683
|
-
end
|
684
|
-
```
|
685
|
-
|
686
|
-
```ruby
|
687
|
-
PowerStencil DSL> e = new_custom_entity name: :test_entity
|
688
|
-
=> #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'>
|
689
|
-
PowerStencil DSL> sub_prop1 = new_base_entity name: :prop1
|
690
|
-
=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>
|
691
|
-
PowerStencil DSL> e.sub_properties << sub_prop1
|
692
|
-
=> [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>]
|
693
|
-
PowerStencil DSL> sub_prop2 = new_base_entity name: :prop2
|
694
|
-
=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>
|
695
|
-
PowerStencil DSL> e.sub_properties << sub_prop2
|
696
|
-
=> [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>,
|
697
|
-
#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>]
|
698
|
-
PowerStencil DSL> sub_prop1.save
|
699
|
-
=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>
|
700
|
-
PowerStencil DSL> sub_prop2.save
|
701
|
-
=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>
|
702
|
-
PowerStencil DSL> e.save
|
703
|
-
=> #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'>
|
704
|
-
PowerStencil DSL> exit
|
705
|
-
```
|
706
|
-
|
707
|
-
Which translates at persistence level as:
|
708
|
-
|
709
|
-
```shell
|
710
|
-
--- !ruby/object:MyCustomEntity
|
711
|
-
:sub_properties:
|
712
|
-
- !psref
|
713
|
-
type: :base_entity
|
714
|
-
name: prop1
|
715
|
-
- !psref
|
716
|
-
type: :base_entity
|
717
|
-
name: prop2
|
718
|
-
:name: test_entity
|
719
|
-
```
|
720
|
-
Nice !
|
721
|
-
|
722
|
-
**:warning: See more advanced features, like reverse methods in the [universe_compiler advanced relations documentation].**
|
723
|
-
|
724
|
-
### is_array
|
621
|
+
#### is_array
|
725
622
|
|
726
623
|
You can define a field as being an array:
|
727
624
|
|
@@ -745,7 +642,7 @@ PowerStencil DSL> e.fields
|
|
745
642
|
|
746
643
|
:information_source: Please note the two syntaxes are equivalent.
|
747
644
|
|
748
|
-
|
645
|
+
#### is_hash
|
749
646
|
|
750
647
|
You can define a field as being an array:
|
751
648
|
|
@@ -769,7 +666,7 @@ PowerStencil DSL> e.fields
|
|
769
666
|
|
770
667
|
:information_source: Please note the two syntaxes are equivalent.
|
771
668
|
|
772
|
-
|
669
|
+
#### not_null
|
773
670
|
|
774
671
|
I guess you start getting used to what happens:
|
775
672
|
|
@@ -804,7 +701,7 @@ PowerStencil DSL> e.valid?
|
|
804
701
|
```
|
805
702
|
Nothing very surprising there. Please note an empty string is not a null value...
|
806
703
|
|
807
|
-
|
704
|
+
#### not_empty
|
808
705
|
|
809
706
|
This directive will adapt depending on the field type
|
810
707
|
|
@@ -847,7 +744,7 @@ Pretty simple nope ?
|
|
847
744
|
|
848
745
|
:information_source: `has_one` does not support `not_empty` but support `not_null`, and the opposite for `has_many`...
|
849
746
|
|
850
|
-
|
747
|
+
#### should_match
|
851
748
|
|
852
749
|
`should_match` will perform a validation of the content regarding a regular expression or a string. It should work on strings or symbols:
|
853
750
|
|
@@ -888,7 +785,7 @@ PowerStencil DSL> e.valid? raise_error: true
|
|
888
785
|
|
889
786
|
:warning: As you can see there, unless specified as `not_null` or `not_empty`, the `should_match` validation will not be performed ! Pretty normal if you think about it...
|
890
787
|
|
891
|
-
|
788
|
+
#### class_name
|
892
789
|
|
893
790
|
```ruby
|
894
791
|
class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity
|
@@ -917,6 +814,119 @@ PowerStencil DSL> e.valid? raise_error: true
|
|
917
814
|
|
918
815
|
:warning: Use this one with caution, as it does not test anything regarding inheritance...
|
919
816
|
|
817
|
+
|
818
|
+
### Relational constraints
|
819
|
+
|
820
|
+
#### has_one
|
821
|
+
|
822
|
+
This property may look familiar to users of [ActiveRecord], it introduces the concept of relationship between entities.
|
823
|
+
|
824
|
+
```ruby
|
825
|
+
class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity
|
826
|
+
entity_type :custom_entity
|
827
|
+
|
828
|
+
has_one :custom_entity, name: :parent
|
829
|
+
end
|
830
|
+
```
|
831
|
+
|
832
|
+
```ruby
|
833
|
+
PowerStencil DSL> e = new_custom_entity name: :test_entity
|
834
|
+
=> #<MyCustomEntity:47215552142260 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566478203.584915)'>
|
835
|
+
PowerStencil DSL> p = new_custom_entity name: :foo
|
836
|
+
=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>
|
837
|
+
PowerStencil DSL> e.parent = p
|
838
|
+
=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>
|
839
|
+
PowerStencil DSL> e.fields
|
840
|
+
=> {:name=>"test_entity", :parent=>#<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>}
|
841
|
+
PowerStencil DSL> p.save=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>
|
842
|
+
PowerStencil DSL> e.save
|
843
|
+
=> #<MyCustomEntity:47215552142260 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566478203.584915)'>
|
844
|
+
PowerStencil DSL> exit
|
845
|
+
```
|
846
|
+
|
847
|
+
Which translates at persistence level as:
|
848
|
+
|
849
|
+
```shell
|
850
|
+
$ power_stencil get custom_entity/test_entity --raw
|
851
|
+
--- !ruby/object:MyCustomEntity
|
852
|
+
:name: test_entity
|
853
|
+
:parent: !psref
|
854
|
+
type: :custom_entity
|
855
|
+
name: foo
|
856
|
+
```
|
857
|
+
Here we are referencing an entity of the same type, but of course you can reference any type of entity. Using `has_one` will enforce the type of data you reference. Let's try to mess-up:
|
858
|
+
|
859
|
+
```ruby
|
860
|
+
PowerStencil DSL> e.parent = :bar
|
861
|
+
=> :bar
|
862
|
+
PowerStencil DSL> e.fields
|
863
|
+
=> {:name=>"test_entity", :parent=>:bar}
|
864
|
+
PowerStencil DSL> e.valid?
|
865
|
+
=> false
|
866
|
+
PowerStencil DSL> e.valid? raise_error: true
|
867
|
+
UniverseCompiler::Error: Invalid entity '[:custom_entity, "test_entity"]' for fields parent !
|
868
|
+
from /opt/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/universe_compiler-0.2.7/lib/universe_compiler/utils/error_propagation.rb:10:in `false_or_raise'
|
869
|
+
PowerStencil DSL> e.save
|
870
|
+
UniverseCompiler::Error: Invalid entity '[:custom_entity, "test_entity"]' for fields parent !
|
871
|
+
from /opt/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/universe_compiler-0.2.7/lib/universe_compiler/utils/error_propagation.rb:10:in `false_or_raise'
|
872
|
+
```
|
873
|
+
So you see that if we try to set parent with something wrong, the accessor seems to accept, you can even see the `#fields` Hash updated. But as soon as you try to save to entity, or if you use the `#valid?` method, it complains about the type... Cool.
|
874
|
+
|
875
|
+
:information_source: The `name` property of the `has_one` directive is optional. If not present the field will be named from the entity_type referenced instead...
|
876
|
+
|
877
|
+
**:information_source: See more advanced features, like the very powerful reverse methods in the [`universe_compiler` advanced relations documentation].**
|
878
|
+
|
879
|
+
#### has_many
|
880
|
+
|
881
|
+
Once you know the `has_one` directive, you should not be surprised by the `has_many` directive...
|
882
|
+
|
883
|
+
```ruby
|
884
|
+
class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity
|
885
|
+
entity_type :custom_entity
|
886
|
+
|
887
|
+
has_many :base_entity, name: :sub_properties
|
888
|
+
end
|
889
|
+
```
|
890
|
+
|
891
|
+
```ruby
|
892
|
+
PowerStencil DSL> e = new_custom_entity name: :test_entity
|
893
|
+
=> #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'>
|
894
|
+
PowerStencil DSL> sub_prop1 = new_base_entity name: :prop1
|
895
|
+
=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>
|
896
|
+
PowerStencil DSL> e.sub_properties << sub_prop1
|
897
|
+
=> [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>]
|
898
|
+
PowerStencil DSL> sub_prop2 = new_base_entity name: :prop2
|
899
|
+
=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>
|
900
|
+
PowerStencil DSL> e.sub_properties << sub_prop2
|
901
|
+
=> [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>,
|
902
|
+
#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>]
|
903
|
+
PowerStencil DSL> sub_prop1.save
|
904
|
+
=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>
|
905
|
+
PowerStencil DSL> sub_prop2.save
|
906
|
+
=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>
|
907
|
+
PowerStencil DSL> e.save
|
908
|
+
=> #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'>
|
909
|
+
PowerStencil DSL> exit
|
910
|
+
```
|
911
|
+
|
912
|
+
Which translates at persistence level as:
|
913
|
+
|
914
|
+
```shell
|
915
|
+
--- !ruby/object:MyCustomEntity
|
916
|
+
:sub_properties:
|
917
|
+
- !psref
|
918
|
+
type: :base_entity
|
919
|
+
name: prop1
|
920
|
+
- !psref
|
921
|
+
type: :base_entity
|
922
|
+
name: prop2
|
923
|
+
:name: test_entity
|
924
|
+
```
|
925
|
+
Nice !
|
926
|
+
|
927
|
+
**:information_source: See more advanced features, like the very powerful reverse methods in the [`universe_compiler` advanced relations documentation].**
|
928
|
+
|
929
|
+
|
920
930
|
### buildable and buildable_by
|
921
931
|
|
922
932
|
One of the most important directives !
|
@@ -973,5 +983,5 @@ Now you know an entity type is just a regular Ruby class. As such you could add
|
|
973
983
|
[ActiveRecord]: https://guides.rubyonrails.org/active_record_basics.html "The ultimate ORM"
|
974
984
|
[Ruby On Rails]: https://rubyonrails.org/ "One of the best Web framework"
|
975
985
|
[universe_compiler]: https://gitlab.com/tools4devops/universe_compiler "The underlying engine to manage entities and compilation !"
|
976
|
-
[universe_compiler advanced relations documentation]: https://gitlab.com/tools4devops/universe_compiler#advanced-relations "Advanced relational features"
|
986
|
+
[`universe_compiler` advanced relations documentation]: https://gitlab.com/tools4devops/universe_compiler#advanced-relations "Advanced relational features"
|
977
987
|
[Graphviz]: (https://www.graphviz.org/) "Graph Visualization Software"
|
data/doc/example_use_cases.md
CHANGED
@@ -17,6 +17,7 @@ Example use cases
|
|
17
17
|
Considering the genericity of the `PowerStencil` framework, it is a bit difficult to define a strict scope for its usage. It's a bit like wondering what you could do with a programming language.
|
18
18
|
|
19
19
|
Neverthless, I will give two short ideas that should open you mind to things you could do with it.
|
20
|
+
Plugins are currently in development around these topics, and may come pretty soon.
|
20
21
|
|
21
22
|
|
22
23
|
# Managing machines, routers, firewalls...
|
@@ -29,6 +30,8 @@ You could define machines, interfaces, networks as [entities] and having [templa
|
|
29
30
|
|
30
31
|
And of course, changes are tracked using Git, providing easy fallback for something as critical as your network config.
|
31
32
|
|
33
|
+
An official plugin is under development for this.
|
34
|
+
|
32
35
|
# Deploying Snaps, Docker containers, VMs
|
33
36
|
|
34
37
|
If you manage a containerized infrastructure, you probably noticed how often you need to have the same information duplicated from your application builds, Snaps, Docker containers or VM definitions (names, ports, entry-points...)
|
data/doc/faq.md
CHANGED
@@ -70,16 +70,17 @@ Regarding Windows, I stopped using spywareOS years ago so I can't really tell yo
|
|
70
70
|
|
71
71
|
# What is the status of `PowerStencil` ?
|
72
72
|
|
73
|
-
|
73
|
+
`PowerStencil` is still under development, yet **it can already be safely used**.
|
74
74
|
|
75
75
|
Regarding `PowerStencil` core:
|
76
76
|
|
77
77
|
- The part that may evolve the most is the plugin part (including documentation which is not really in par with the rest...), but it should not break anything developed now.
|
78
|
-
- New system entity types may appear.
|
78
|
+
- New system entity types may appear.
|
79
|
+
- The documentation is evolving
|
79
80
|
|
80
81
|
Anyway `PowerStencil` follows the semantic versioning pattern and if incompatible changes arise it may be reflected in the version.
|
81
82
|
|
82
|
-
There are already some plugins in the pipe,
|
83
|
+
There are already some plugins in the pipe. See [example use cases], to get an idea of the first official plugins to come.
|
83
84
|
|
84
85
|
:information_source: Of course, `PowerStencil` is new software and it is expected to evolve with the needs of its users...
|
85
86
|
|
@@ -94,6 +95,7 @@ There are already some plugins in the pipe, especially around contenerization to
|
|
94
95
|
[entities]: entities.md "Entities in PowerStencil"
|
95
96
|
[plugins]: plugins.md "Plugins in PowerStencil"
|
96
97
|
[overrides]: builds.md#overriding-entities-and-build-scenarii "Overriding data locally"
|
98
|
+
[example use cases]: example_use_cases.md "Example uses cases using PowerStencil"
|
97
99
|
|
98
100
|
|
99
101
|
<!-- Code links -->
|
data/doc/templates.md
CHANGED
@@ -19,15 +19,19 @@ Templates
|
|
19
19
|
|
20
20
|
# Templates overview
|
21
21
|
|
22
|
-
|
22
|
+
Template is a key feature of `PowerStencil` (hence the name). In templates you define how you will use the [entities] you carefully crafted in order to produce something during a [build][builds] process.
|
23
23
|
|
24
|
-
|
24
|
+
The default templating engine being [ERB], your templates should be written using the [ERB] syntax, like most templates are written in the [Ruby On Rails] framework. This is basically some [Ruby] inside some ERB tags.
|
25
25
|
|
26
|
-
|
26
|
+
Templates are always associated to some [buildable entities][buildable].
|
27
|
+
|
28
|
+
When a [buildable entity][buildable] has some templates associated, they will be located in a directory `<entity_type>/<entity_name>/`. For some entity types, when you will create a new entity of this type, some default templates will be created in that directory (this is the case of the `simple_exec` entity type as you will see in the next paragraph). This is what is called `templates-templates`.
|
29
|
+
|
30
|
+
In this document, you will learn how to create your own templates, as well as your own templates-templates.
|
27
31
|
|
28
32
|
# Templates discovery with `simple_exec` entity type
|
29
33
|
|
30
|
-
In the basic entity types, the only one
|
34
|
+
In the basic entity types, the only one providing default templates is the `simple_exec` entity type. So let's try with it:
|
31
35
|
|
32
36
|
```shell
|
33
37
|
$ power_stencil create simple_exec/demo_templates
|
@@ -41,9 +45,9 @@ RAW ENTITIES
|
|
41
45
|
- Status : Valid
|
42
46
|
- Buildable : true
|
43
47
|
```
|
44
|
-
As you can see the output of `power_stencil check` shows more information than entities we
|
48
|
+
As you can see the output of `power_stencil check` shows more information than entities we created so far. First we see that this entity is `buildable`, and we'll detail that in the [builds] document, but for the moment what we will focus on the `Templates path` information.
|
45
49
|
|
46
|
-
And it's true if we have a look in the `simple_exec/demo_templates
|
50
|
+
And it's true if we have a look in the `simple_exec/demo_templates/` directory from the root of the project, a file appeared there:
|
47
51
|
|
48
52
|
```shell
|
49
53
|
$ ls -l simple_exec/demo_templates
|
@@ -138,7 +142,7 @@ Here are the main methods:
|
|
138
142
|
- `entity(type, name)` will return any entity from the repository. The method is self-explanatory, this is the most generic way to access any entity of the repository.
|
139
143
|
- `entities(criterion: nil, value: nil, &filter_block)` which is a more generic entities query method where `criterion` can be `:by_name` or `:by_type` and that will return an array (that you can potentially filter using the `filter_block`).
|
140
144
|
- `build_target` will return the entity that you are currently building.
|
141
|
-
- `project_config` is a shortcut to the project entity. You could actually retrieve it using the `entity(
|
145
|
+
- `project_config` is a shortcut to the project entity. You could actually retrieve it using the `entity(:project_config, 'Project Config')` method.
|
142
146
|
|
143
147
|
And of course you have access like in `power_stencil shell` to any class brought by `PowerStencil`, you could create entities there, destroy some, **but you should not do it**, as it would be very weird to do that during the process of detemplating !
|
144
148
|
|
@@ -21,10 +21,18 @@ module PowerStencil
|
|
21
21
|
h = entity.to_hash
|
22
22
|
entity.class.fields_constraints.each do |field_name, constraints|
|
23
23
|
next unless constraints[:reverse_method]
|
24
|
+
|
24
25
|
reverse_method_conf = constraints[:reverse_method]
|
25
26
|
val = entity.send(reverse_method_conf[:actual_method])
|
26
27
|
node = h[entity.class.name][:dynamic_data] ||= {}
|
27
|
-
|
28
|
+
next if val.nil?
|
29
|
+
next if val.is_a? Array and val.empty?
|
30
|
+
|
31
|
+
node[reverse_method_conf[:actual_method]] = if val.is_a? Array
|
32
|
+
val.map &:as_path
|
33
|
+
else
|
34
|
+
val.as_path
|
35
|
+
end
|
28
36
|
end
|
29
37
|
puts h.to_yaml
|
30
38
|
end
|
@@ -13,6 +13,10 @@ module PowerStencil
|
|
13
13
|
e.nil? ? entity(type.to_sym, name) : e
|
14
14
|
end
|
15
15
|
|
16
|
+
def project_config
|
17
|
+
entity :project_config, 'Project Config'
|
18
|
+
end
|
19
|
+
|
16
20
|
def entity(type_or_path, name = nil)
|
17
21
|
type, name = if name.nil?
|
18
22
|
md = type_or_path.match /^(?<type>[^\/]+)\/(?<name>.*)$/
|
data/power_stencil.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
|
28
28
|
spec.add_dependency 'climatic', '~> 0.2.29'
|
29
29
|
spec.add_dependency 'dir_glob_ignore', '~> 0.3'
|
30
|
-
spec.add_dependency 'universe_compiler', '~> 0.4.
|
30
|
+
spec.add_dependency 'universe_compiler', '~> 0.4.3'
|
31
31
|
spec.add_dependency 'pry'
|
32
32
|
|
33
33
|
spec.post_install_message = %Q{
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: power_stencil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Laurent B.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-09-
|
11
|
+
date: 2019-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.4.
|
89
|
+
version: 0.4.3
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.4.
|
96
|
+
version: 0.4.3
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: pry
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -253,7 +253,7 @@ homepage: https://gitlab.com/tools4devops/power_stencil
|
|
253
253
|
licenses:
|
254
254
|
- MIT
|
255
255
|
metadata: {}
|
256
|
-
post_install_message: "\nThank you for installing PowerStencil 0.4.
|
256
|
+
post_install_message: "\nThank you for installing PowerStencil 0.4.7 !\nFrom the command
|
257
257
|
line you can run `power_stencil --help`\nIf your shell is not completing the command:\n
|
258
258
|
\ If you use rbenv: `rbenv rehash`\n If you use zsh : `rehash`\n\nFull documentation
|
259
259
|
here : https://gitlab.com/tools4devops/power_stencil/blob/master/README.md\nFeel
|