power_stencil 0.4.2 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 397ae8708dcf83c49787aa22e1ef23360c136ba7
4
- data.tar.gz: b504e3d431b71a01f70a1315e20122bce6ba0681
3
+ metadata.gz: 0422be311b723e5ba9d9f58e0884b73964359b96
4
+ data.tar.gz: 594d2a82611aef291f2dfcf9237282d1dcd4a0d0
5
5
  SHA512:
6
- metadata.gz: 65dc07d1a0b556782f3a3b67bb8d430084b6ed6cd35bf9c9e7764d5a9d8e2d51dabf49a5392ba07cbb2e1a0fa224dd981b4503f37fb9b5ef5ded0394c367c042
7
- data.tar.gz: ace8effec5fd7ed0d4fe8401917e71f245f074853093fff4dbb5768917d4e3351553e7abd0d24e708844c0e98c90e2ce13776dfd08aebb8b941ffa804400c7b8
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 !!**. Use the best method depending on what you are doing.
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 the project data
44
- - Manage templates
45
- - Manage builds
46
- - Create and manipulate plugins
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** per se. Instead it uses already existing and proven templating engines.
51
- Currently it uses [ERB], which is pretty standard in [Ruby] world, but this is not hardcoded and any templating engine could be used (in parallel, meaning different templating engines can be used automatically depending on what you actually want to generate), even if only [ERB] is implemented for the time-being, `PowerStencil` is modular from ground-up and at least a second implementation for [Haml] templating engine is planned to ease generation of XML-like files, still currently you can do it with [ERB]. See the [templates] section for more information about templates in `PowerStencil`.
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.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
- 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 any action regarding `PowerStencil` project files.
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
- The project has two distinct config files. Keep the official project config in the `.ps_project/versioned-config.yaml` which, as its name suggest will be versioned. 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. 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.
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
- There is the same mechanism between `.ps_project/entities` and `.ps_project/user_entities`, but as opposed to the two aforementioned config files you should not edit anything directly there, but instead interact using the CLI. More information on how to manage entities [here][entities].
163
+ The project has two distinct config files.
154
164
 
155
- 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. See the [plugins] documentation.
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
- The core of the system is the `entity`, so you should start by having a look at what entities are, how they are easily managed using the `PowerStencil` CLI and shell.
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
- > :arrow_forward: [Entities]
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
- Then it is important to understand how to use entities within `templates`. Templates are the way to generate something (doc, code, descriptors, sites, whatever...) from the data that the entities represent.
182
+ ### Templates
164
183
 
165
- > :arrow_forward: [Templates]
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
- The mechanism that combines entities and templates is called a `build`. 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).
186
+ ### Builds
168
187
 
169
- > :arrow_forward: [Builds]
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
- `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`, further control relations between entities, implement complex post-build actions, add CLI sub-commands and options. Plugins can be local to the project or coming in the form of standard Ruby Gems ! The icing on the cake...
190
+ ### Plugins
172
191
 
173
- > :arrow_forward: [Plugins]
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
- And course, you may:
195
+ <br>
196
+ <br>
176
197
 
177
- - Read the [F.A.Q.]
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"
@@ -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
- - [has_one](#has_one)
29
- - [has_many](#has_many)
30
- - [is_array](#is_array)
31
- - [is_hash](#is_hash)
32
- - [not_null](#not_null)
33
- - [not_empty](#not_empty)
34
- - [should_match](#should_match)
35
- - [class_name](#class_name)
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,112 +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
- This property may look familiar to users of [ActiveRecord], it introduces the concept of relationship between entities.
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
- ```
626
-
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.
618
+ ### Integrity constraints
669
619
 
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
-
672
- ### has_many
673
-
674
- Once you know the `has_one` directive, you should not be surprised by the `has_many` directive...
675
-
676
- ```ruby
677
- class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity
678
- entity_type :custom_entity
679
-
680
- has_many :base_entity, name: :sub_properties
681
- end
682
- ```
683
-
684
- ```ruby
685
- PowerStencil DSL> e = new_custom_entity name: :test_entity
686
- => #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'>
687
- PowerStencil DSL> sub_prop1 = new_base_entity name: :prop1
688
- => #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>
689
- PowerStencil DSL> e.sub_properties << sub_prop1
690
- => [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>]
691
- PowerStencil DSL> sub_prop2 = new_base_entity name: :prop2
692
- => #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>
693
- PowerStencil DSL> e.sub_properties << sub_prop2
694
- => [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>,
695
- #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>]
696
- PowerStencil DSL> sub_prop1.save
697
- => #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>
698
- PowerStencil DSL> sub_prop2.save
699
- => #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>
700
- PowerStencil DSL> e.save
701
- => #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'>
702
- PowerStencil DSL> exit
703
- ```
704
-
705
- Which translates at persistence level as:
706
-
707
- ```shell
708
- --- !ruby/object:MyCustomEntity
709
- :sub_properties:
710
- - !psref
711
- type: :base_entity
712
- name: prop1
713
- - !psref
714
- type: :base_entity
715
- name: prop2
716
- :name: test_entity
717
- ```
718
- Nice !
719
620
 
720
- ### is_array
621
+ #### is_array
721
622
 
722
623
  You can define a field as being an array:
723
624
 
@@ -741,7 +642,7 @@ PowerStencil DSL> e.fields
741
642
 
742
643
  :information_source: Please note the two syntaxes are equivalent.
743
644
 
744
- ### is_hash
645
+ #### is_hash
745
646
 
746
647
  You can define a field as being an array:
747
648
 
@@ -765,7 +666,7 @@ PowerStencil DSL> e.fields
765
666
 
766
667
  :information_source: Please note the two syntaxes are equivalent.
767
668
 
768
- ### not_null
669
+ #### not_null
769
670
 
770
671
  I guess you start getting used to what happens:
771
672
 
@@ -800,7 +701,7 @@ PowerStencil DSL> e.valid?
800
701
  ```
801
702
  Nothing very surprising there. Please note an empty string is not a null value...
802
703
 
803
- ### not_empty
704
+ #### not_empty
804
705
 
805
706
  This directive will adapt depending on the field type
806
707
 
@@ -843,7 +744,7 @@ Pretty simple nope ?
843
744
 
844
745
  :information_source: `has_one` does not support `not_empty` but support `not_null`, and the opposite for `has_many`...
845
746
 
846
- ### should_match
747
+ #### should_match
847
748
 
848
749
  `should_match` will perform a validation of the content regarding a regular expression or a string. It should work on strings or symbols:
849
750
 
@@ -884,7 +785,7 @@ PowerStencil DSL> e.valid? raise_error: true
884
785
 
885
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...
886
787
 
887
- ### class_name
788
+ #### class_name
888
789
 
889
790
  ```ruby
890
791
  class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity
@@ -913,6 +814,119 @@ PowerStencil DSL> e.valid? raise_error: true
913
814
 
914
815
  :warning: Use this one with caution, as it does not test anything regarding inheritance...
915
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
+
916
930
  ### buildable and buildable_by
917
931
 
918
932
  One of the most important directives !
@@ -969,4 +983,5 @@ Now you know an entity type is just a regular Ruby class. As such you could add
969
983
  [ActiveRecord]: https://guides.rubyonrails.org/active_record_basics.html "The ultimate ORM"
970
984
  [Ruby On Rails]: https://rubyonrails.org/ "One of the best Web framework"
971
985
  [universe_compiler]: https://gitlab.com/tools4devops/universe_compiler "The underlying engine to manage entities and compilation !"
986
+ [`universe_compiler` advanced relations documentation]: https://gitlab.com/tools4devops/universe_compiler#advanced-relations "Advanced relational features"
972
987
  [Graphviz]: (https://www.graphviz.org/) "Graph Visualization Software"
@@ -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
- Although `PowerStencil` is still under development, **it can already be safely used**.
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, especially around contenerization topics.
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 -->
@@ -19,15 +19,19 @@ Templates
19
19
 
20
20
  # Templates overview
21
21
 
22
- Templates are the key feature of `PowerStencil` (hence the name). Templates are what will use the [entities] you carefully crafted in order to produce something during the [build][builds] process.
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
- Currently the underlying engine is [ERB].
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
- When an entity type has some templates associated and you create an entity, it will create a directory `<entity_type>/<entity_name>` where you will fond those templates.
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 having templates is the `simple_exec` entity type. So let's try with it:
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 already created. 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.
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` from the root of the project, a file appeared there:
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(type, name)` method.
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
 
@@ -17,6 +17,7 @@
17
17
  # :labelloc: :t
18
18
  # :show_config: false
19
19
  # :file_type: svg
20
+ # :graph_type: :digraph
20
21
  # :node:
21
22
  # :shape: box
22
23
  # :style: filled
@@ -90,6 +90,7 @@
90
90
  :labelloc: :t
91
91
  :show_config: false
92
92
  :file_type: :svg
93
+ :graph_type: :digraph
93
94
  :node:
94
95
  :shape: box
95
96
  :style: filled
@@ -17,6 +17,7 @@
17
17
  # :labelloc: :t
18
18
  # :show_config: false
19
19
  # :file_type: svg
20
+ # :graph_type: :digraph
20
21
  # :node:
21
22
  # :shape: box
22
23
  # :style: filled
@@ -17,7 +17,24 @@ module PowerStencil
17
17
  if config[:raw]
18
18
  puts entity.to_yaml
19
19
  else
20
- puts entity.to_hash.to_yaml
20
+ # Display entity including data coming from reverse methods
21
+ h = entity.to_hash
22
+ entity.class.fields_constraints.each do |field_name, constraints|
23
+ next unless constraints[:reverse_method]
24
+
25
+ reverse_method_conf = constraints[:reverse_method]
26
+ val = entity.send(reverse_method_conf[:actual_method])
27
+ node = h[entity.class.name][:dynamic_data] ||= {}
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
36
+ end
37
+ puts h.to_yaml
21
38
  end
22
39
  puts
23
40
  end
@@ -14,10 +14,6 @@ module PowerStencil
14
14
  @universe = universe
15
15
  end
16
16
 
17
- def project_config
18
- project.config
19
- end
20
-
21
17
  end
22
18
 
23
19
  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>.*)$/
@@ -11,9 +11,14 @@ module PowerStencil
11
11
  else
12
12
  entities
13
13
  end
14
- graph_entities_to_file entities_to_process,
15
- output_file_name: filename,
16
- file_type: config[:graphviz][:file_type] do |graph, cache|
14
+
15
+ graph_options = {
16
+ output_file_name: filename,
17
+ graph_type: config[:graphviz][:graph_type],
18
+ file_type: config[:graphviz][:file_type]
19
+ }
20
+
21
+ graph_entities_to_file entities_to_process, graph_options do |graph, cache|
17
22
  graph[:label] = config[:graphviz][:label]
18
23
  graph[:labelloc] = config[:graphviz][:labelloc]
19
24
  graph.each_node do |node_name|
@@ -1,3 +1,3 @@
1
1
  module PowerStencil
2
- VERSION = '0.4.2'.freeze
2
+ VERSION = '0.4.7'.freeze
3
3
  end
@@ -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.3.9'
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.2
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-16 00:00:00.000000000 Z
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.3.9
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.3.9
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.2 !\nFrom the command
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