universe_compiler 0.2.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +183 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +3 -0
  5. data/.travis.yml +4 -0
  6. data/CODE_OF_CONDUCT.md +49 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +318 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +10 -0
  12. data/bin/setup +8 -0
  13. data/lib/universe_compiler/entity/auto_named.rb +31 -0
  14. data/lib/universe_compiler/entity/conversion.rb +66 -0
  15. data/lib/universe_compiler/entity/field_binder.rb +36 -0
  16. data/lib/universe_compiler/entity/field_constraint_management.rb +95 -0
  17. data/lib/universe_compiler/entity/field_management.rb +57 -0
  18. data/lib/universe_compiler/entity/inheritance.rb +87 -0
  19. data/lib/universe_compiler/entity/inheritance_merge_policy.rb +19 -0
  20. data/lib/universe_compiler/entity/marshalling.rb +71 -0
  21. data/lib/universe_compiler/entity/overridden.rb +31 -0
  22. data/lib/universe_compiler/entity/persistence.rb +34 -0
  23. data/lib/universe_compiler/entity/reference.rb +77 -0
  24. data/lib/universe_compiler/entity/relations_management.rb +46 -0
  25. data/lib/universe_compiler/entity/type_management.rb +43 -0
  26. data/lib/universe_compiler/entity/validation.rb +92 -0
  27. data/lib/universe_compiler/entity.rb +64 -0
  28. data/lib/universe_compiler/error.rb +15 -0
  29. data/lib/universe_compiler/override.rb +24 -0
  30. data/lib/universe_compiler/package/bootstrap.rb +46 -0
  31. data/lib/universe_compiler/package.rb +17 -0
  32. data/lib/universe_compiler/persistence/basic_yaml_engine.rb +68 -0
  33. data/lib/universe_compiler/persistence/management.rb +30 -0
  34. data/lib/universe_compiler/universe/compile.rb +45 -0
  35. data/lib/universe_compiler/universe/duplication.rb +62 -0
  36. data/lib/universe_compiler/universe/entities.rb +52 -0
  37. data/lib/universe_compiler/universe/index.rb +40 -0
  38. data/lib/universe_compiler/universe/multiverse.rb +44 -0
  39. data/lib/universe_compiler/universe/persistence.rb +23 -0
  40. data/lib/universe_compiler/universe/query.rb +45 -0
  41. data/lib/universe_compiler/universe/validation.rb +30 -0
  42. data/lib/universe_compiler/universe.rb +38 -0
  43. data/lib/universe_compiler/utils/array_utils.rb +59 -0
  44. data/lib/universe_compiler/utils/basic_logger.rb +24 -0
  45. data/lib/universe_compiler/utils/deep_traverse.rb +61 -0
  46. data/lib/universe_compiler/utils/error_propagation.rb +20 -0
  47. data/lib/universe_compiler/utils/with_unique_name.rb +75 -0
  48. data/lib/universe_compiler/version.rb +3 -0
  49. data/lib/universe_compiler.rb +60 -0
  50. data/universe_compiler.gemspec +32 -0
  51. metadata +218 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fcdb61ff730d5df5a1e0f6117d0a992efc00e5ca
4
+ data.tar.gz: 1eb29fbfe6f5bb1b25546e27b874cd952eb86569
5
+ SHA512:
6
+ metadata.gz: d09a32e939341ab78b41f265efdab69512a5adf29e1abb1be65e87cfa92448823e2bf49007df317fe90a2c4d8d0ec948bfce78c5f0122a53cc11cec3e89f96c8
7
+ data.tar.gz: 74b250059abf728d8df27ada84439da8025fc2fd1e310e70ff9626eb7ec3c02d67059456f5a846b33274e9346b52d453e01976f28f7258504b96b87b909f85da
data/.gitignore ADDED
@@ -0,0 +1,183 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ ### Standard Brewlabs Gem template
11
+ ### Ruby template
12
+ *.gem
13
+ *.rbc
14
+ /.config
15
+ /InstalledFiles
16
+ /spec/examples.txt
17
+ /test/tmp/
18
+ /test/version_tmp/
19
+
20
+ # Used by dotenv library to load environment variables.
21
+ # .env
22
+
23
+ ## Specific to RubyMotion:
24
+ .dat*
25
+ .repl_history
26
+ build/
27
+ *.bridgesupport
28
+ build-iPhoneOS/
29
+ build-iPhoneSimulator/
30
+
31
+ ## Specific to RubyMotion (use of CocoaPods):
32
+ #
33
+ # We recommend against adding the Pods directory to your .gitignore. However
34
+ # you should judge for yourself, the pros and cons are mentioned at:
35
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
36
+ #
37
+ # vendor/Pods/
38
+
39
+ ## Documentation cache and generated files:
40
+ /.yardoc/
41
+ /rdoc/
42
+
43
+ ## Environment normalization:
44
+ /vendor/bundle
45
+ /lib/bundler/man/
46
+
47
+ # for a library or gem, you might want to ignore these files since the code is
48
+ # intended to run in multiple environments; otherwise, check them in:
49
+ # Gemfile.lock
50
+ # .ruby-version
51
+ # .ruby-gemset
52
+
53
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
54
+ .rvmrc
55
+ ### SublimeText template
56
+ # cache files for sublime text
57
+ *.tmlanguage.cache
58
+ *.tmPreferences.cache
59
+ *.stTheme.cache
60
+
61
+ # workspace files are user-specific
62
+ *.sublime-workspace
63
+
64
+ # project files should be checked into the repository, unless a significant
65
+ # proportion of contributors will probably not be using SublimeText
66
+ # *.sublime-project
67
+
68
+ # sftp configuration file
69
+ sftp-config.json
70
+
71
+ # Package control specific files
72
+ Package Control.last-run
73
+ Package Control.ca-list
74
+ Package Control.ca-bundle
75
+ Package Control.system-ca-bundle
76
+ Package Control.cache/
77
+ Package Control.ca-certs/
78
+ bh_unicode_properties.cache
79
+
80
+ # Sublime-github package stores a github token in this file
81
+ # https://packagecontrol.io/packages/sublime-github
82
+ GitHub.sublime-settings
83
+ ### KDevelop4 template
84
+ *.kdev4
85
+ .kdev4/
86
+ ### Linux template
87
+ *~
88
+
89
+ # temporary files which can be created if a process still has a handle open of a deleted file
90
+ .fuse_hidden*
91
+
92
+ # KDE directory preferences
93
+ .directory
94
+
95
+ # Linux trash folder which might appear on any partition or disk
96
+ .Trash-*
97
+
98
+ # .nfs files are created when an open file is removed but is still being accessed
99
+ .nfs*
100
+ ### Eclipse template
101
+
102
+ .metadata
103
+ bin/
104
+ tmp/
105
+ *.tmp
106
+ *.bak
107
+ *.swp
108
+ *~.nib
109
+ local.properties
110
+ .settings/
111
+ .loadpath
112
+ .recommenders
113
+
114
+ # Eclipse Core
115
+ .project
116
+
117
+ # External tool builders
118
+ .externalToolBuilders/
119
+
120
+ # Locally stored "Eclipse launch configurations"
121
+ *.launch
122
+
123
+ # PyDev specific (Python IDE for Eclipse)
124
+ *.pydevproject
125
+
126
+ # CDT-specific (C/C++ Development Tooling)
127
+ .cproject
128
+
129
+ # JDT-specific (Eclipse Java Development Tools)
130
+ .classpath
131
+
132
+ # Java annotation processor (APT)
133
+ .factorypath
134
+
135
+ # PDT-specific (PHP Development Tools)
136
+ .buildpath
137
+
138
+ # sbteclipse plugin
139
+ .target
140
+
141
+ # Tern plugin
142
+ .tern-project
143
+
144
+ # TeXlipse plugin
145
+ .texlipse
146
+
147
+ # STS (Spring Tool Suite)
148
+ .springBeans
149
+
150
+ # Code Recommenders
151
+ .recommenders/
152
+ ### VisualStudioCode template
153
+ .vscode/*
154
+ !.vscode/settings.json
155
+ !.vscode/tasks.json
156
+ !.vscode/launch.json
157
+ !.vscode/extensions.json
158
+ ### JetBrains template
159
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
160
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
161
+
162
+ # User-specific stuff:
163
+ .idea/
164
+
165
+ ## File-based project format:
166
+ *.iws
167
+
168
+ ## Plugin-specific files:
169
+
170
+ # IntelliJ
171
+ /out/
172
+
173
+ # mpeltonen/sbt-idea plugin
174
+ .idea_modules/
175
+
176
+ # JIRA plugin
177
+ atlassian-ide-plugin.xml
178
+
179
+ # Crashlytics plugin (for Android Studio and IntelliJ)
180
+ com_crashlytics_export_strings.xml
181
+ crashlytics.properties
182
+ crashlytics-build.properties
183
+ fabric.properties
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ Metrics/LineLength:
3
+ Max: 132
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.4
4
+ before_install: gem install bundler -v 1.11.2
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at lbnetid+gh@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in universe_compiler.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Laurent B.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,318 @@
1
+ # UniverseCompiler
2
+
3
+ The goal of this gem is to provide a simple way to manage a consistent highly complex configuration.
4
+
5
+ The configuration can be split into lot of objects (or `entities`) and complex relations and constraints
6
+ can be defined between them using a-la-ActiveRecord relationships like `has_many` or `is_array` (see
7
+ complete list in `lib/universe_compiler/entity/field_constraint_management.rb`).
8
+
9
+ These entities are added to a so-called `universe`.
10
+ See a universe as a kind of sandbox where entities exist.
11
+
12
+ A `universe` could be _persisted_ to any kind of backend by writing an persistence engine, yet only
13
+ a yaml persistence engine is available by default in the gem.
14
+
15
+ A `universe` can be _compiled_ in order to produce a new `universe` where all constraints and relations defined
16
+ by these entities have been resolved.
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'universe_compiler'
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install universe_compiler
33
+
34
+
35
+ ## Core Concepts
36
+
37
+ ### Entities
38
+
39
+ #### Overview
40
+
41
+ Any `entity` you will create will basically inherit from `UniverseCompiler::Entity::Base`. This will allow
42
+ the following kind of code:
43
+
44
+ ```ruby
45
+ class EntityA < UniverseCompiler::Entity::Base
46
+ entity_type :some_entity
47
+
48
+ field :some_data, :is_hash
49
+ field :bar, :not_null, should_match: /^Y/
50
+ field :stupid
51
+
52
+ has_one EntityA, name: :master
53
+
54
+ end
55
+
56
+ class EntityB < UniverseCompiler::Entity::Base
57
+
58
+ has_many EntityA, name: :some_entities
59
+ not_empty :some_entities
60
+
61
+ end
62
+
63
+ ```
64
+ The core concept is that every entity has a hash property named `fields`. And any field declared using
65
+ the declaration mechanism as above just adds some content validations mechanisms and direct accessors
66
+ to the internal `fields` hash.
67
+
68
+ For example:
69
+
70
+ ```ruby
71
+ a = EntityA.new fields: { stupid: :foo}
72
+
73
+ a.stupid # => :foo
74
+ a.stupid == a[:stupid] # => true
75
+ a.stupid == a.fields[:stupid] # => true
76
+ a.stupid == a['stupid'] # => false, a String is not a Symbol
77
+ ```
78
+
79
+ Therefore the _pseudo schema_ you defined when declaring the class is not limiting... you can always do
80
+
81
+ ```ruby
82
+ a[:non_explicitely_declared_property] = :bar
83
+ a[:non_explicitely_declared_property] # => :bar
84
+ # but
85
+ a.non_explicitely_declared_property # => NoMethodError: undefined method `non_existing_property' for...
86
+ ```
87
+
88
+ Every entity has a `valid?` method which performs various checks. For example here we have said that
89
+ an instance of `EntityB` has many entities of type `EntityA`. You can really see a `has_many` relationship
90
+ an the definition of an Array which content is validated:
91
+
92
+ ```ruby
93
+ b = EntityB.new
94
+ b.valid? # => false
95
+ b.some_entities << :foo
96
+ b.valid? # => false, :foo is not of the expected type
97
+ b.clear
98
+ b.valid? # => false
99
+ b.some_entities << b
100
+ b.valid? # => false, b is not of the expected type
101
+ b.clear
102
+ b.some_entities << a
103
+ b.valid? # => true, a is ok
104
+ ```
105
+ In the same vein:
106
+ ```ruby
107
+ a.valid? # => false
108
+ a.some_entity = a
109
+ a.valid? # => false, still false as requiring a non null :bar property
110
+ a.bar = 'hey man'
111
+ a.valid? # => false, not compliant with regexp specified
112
+ a.bar = 'Yo man'
113
+ a.valid? # => true
114
+ ```
115
+ #### Special directives
116
+
117
+ By default every entity has a `type`. It is available using the `#type` instance method or the
118
+ `::entity_type` class method. The default value for the entity type is coming
119
+ from the class name but it can be overridden using the `entity_type` directive:
120
+ ```ruby
121
+ EntityA.entity_type # => :some_entity
122
+ EntityB.entity_type # => "entity_b"
123
+ a = EntityA.new # => #<EntityA:47429412219120 composite_key=[:some_entity, nil]>
124
+ a.type # => :some_entity
125
+ b = EntityB.new # => #<EntityB:47429411925900 composite_key=["entity_b", nil]>
126
+ b.type # => "entity_b"
127
+ ```
128
+
129
+ The `name` of an entity can be automatically generated using the `auto_named_entity_type`
130
+ directive optionally providing a seed:
131
+
132
+ ```ruby
133
+ class EntityC < UniverseCompiler::Entity::Base
134
+ auto_named_entity_type
135
+ end
136
+ class EntityD < UniverseCompiler::Entity::Base
137
+ auto_named_entity_type :my_seed
138
+ end
139
+
140
+ EntityC.new # => #<EntityC:46943375076460 composite_key=["entity_c", "entity_c_1"]>
141
+ EntityD.new # => #<EntityD:46943378308720 composite_key=["entity_d", "my_seed_1"]>
142
+ EntityD.new # => #<EntityD:46943375641700 composite_key=["entity_d", "my_seed_2"]>
143
+ ```
144
+
145
+
146
+ #### Constraints and relationships directives
147
+
148
+ The generic form to declare a field is the `field` statement. Any constraint can be declared using the `field`
149
+ method. Here is the signature:
150
+
151
+ ```ruby
152
+ def field(field_name, *options)
153
+ ```
154
+
155
+ Then other _constraint_ methods that can be used when describing an entity can be grouped into two. The switches:
156
+
157
+ * not_null
158
+ * not_empty
159
+ * is_array
160
+ * is_hash
161
+
162
+ Then some methods taking parameter:
163
+
164
+ * should_match
165
+ * class_name
166
+
167
+ You have as well relationship methods:
168
+
169
+ * has_one
170
+ * has_many
171
+
172
+ So for each of these methods can be used either as "real" methods or as `field` parameter. For example:
173
+ ```ruby
174
+ class MyEntity < UniverseCompiler::Entity::Base
175
+ field :my_field, :not_null, class_name: AClass
176
+ end
177
+ ```
178
+ Is strictly equivalent to:
179
+ ```ruby
180
+ class MyEntity < UniverseCompiler::Entity::Base
181
+ not_null :my_field
182
+ class_name :my_field, AClass
183
+ end
184
+ ```
185
+ Notice the fact that in the latter form `my_field` is "declared" more than once.
186
+
187
+
188
+ ### Compilation
189
+
190
+ The compilation mechanism is related to universes.
191
+ When compiling a universe it actually:
192
+
193
+ * Creates a __new universe__ containing __deep copies__ of its original entities.
194
+ * Applies entities inheritance defined by the special field `extends`.
195
+ * Applies overrides defined by the `:entity_overide` special entity type.
196
+
197
+ Here is an example
198
+ ```ruby
199
+ u = UniverseCompiler.new_universe
200
+ # Adding entities to universe requires they have a name
201
+ a = EntityA.new fields: { name: :a, bar: 'Yo man', stupid: :yeah } # a is valid
202
+ b = EntityA.new fields: { name: :b, extends: a } # Notice b is not valid but extends a
203
+ u << a << b
204
+
205
+ v = u.compile # v is a new universe result of the "compilation" of u
206
+ u.name # => "Unnamed Universe"
207
+ v.name # => "Unnamed Universe - COMPILED #47332840258780"
208
+
209
+ compiled_b = v.get_entity :some_entity, :b
210
+ compiled_b == b # => true, b and compiled_b although different represent the same entity
211
+ compiled_b.eql? b # => false, b and compiled_b are in different universe
212
+ compiled_b.equal? b # => false, b and compiled_b have different object_id
213
+ b.valid? # => false, in the universe u, b is still not valid
214
+ compiled_b.valid? # => true, thanks to the fact b extends a
215
+ a.fields # => {:name=>:a, :bar=>"Yo man", :stupid=>:yeah, :some_data=>{}}
216
+ b.fields # => {:name=>:b, :extends=>#<EntityA:47405166007800 composite_key=[:some_entity, :a], @universe='Unnamed Universe'>, :some_data=>{}}
217
+ compiled_b.fields # => {:name=>:b, :bar=>"Yo man", :stupid=>:yeah, :some_data=>{}, :extends=>#<EntityA:47405171122480 composite_key=[:some_entity, :a], @universe='Unnamed Universe - COMPILED #47405171131080'>}
218
+ ```
219
+ And each entity in the new universe will have the flag `compiled` set to `true`.
220
+
221
+ ```ruby
222
+ u.get_entities.map do |entity|
223
+ {name: entity.name, compiled: entity.compiled}
224
+ end
225
+ # => [{name: :a, compiled: false},{name: :b, compiled: false},{name: :c, compiled: false}]
226
+ v.get_entities.map do |entity|
227
+ {name: entity.name, compiled: entity.compiled}
228
+ end
229
+ # => [{name: :a, compiled: true},{name: :b, compiled: true},{name: :c, compiled: true}]
230
+ ```
231
+
232
+ ### Inheritance
233
+
234
+ To be clear, here we talk about __entities (instances) inheritance, NOT classes !__
235
+
236
+ Each entity can potentially extend (using the `extends` field) one entity... which itself could extend
237
+ as well another entity. __Circular references are detected and compilation may fail.__
238
+
239
+ When you `extends` another entity, it means that when the universe "compiles", it will perform
240
+ some merge operations. e.g. for the the following inheritance definition:
241
+ ```
242
+ u1.a --extends--> u1.b --extends--> u1.c
243
+ ```
244
+ It means that if you have a universe u1 containing these entities a, b, c and you compile it, the resulting universe,
245
+ let's call it u2, will contain 3 new entities a, b and c which content will be (all content is
246
+ duplicated):
247
+
248
+ * u2.c content is the __same as u1.c__.
249
+ * u2.b content will be __the merge of u1.b into u2.c__.
250
+ * u2.a content will be __the merge of u1.a into u2.b__.
251
+
252
+ Of course the compilation process keeps the initial relationships.
253
+
254
+ ```
255
+ u2.a --extends--> u2.b --extends--> u2.c
256
+ ```
257
+ You can see an example of inheritance in previous paragraph.
258
+
259
+ ### Overrides
260
+
261
+ Overrides are actually a special type of entities. They have a special array called `overrides`
262
+ which contains a list of entities you want to inject content into.
263
+
264
+ When you override entity `a` with override `o`, it means that the content (fields) of `o` will be _injected_
265
+ into `a` (fields). This is why an override can override multiple objects of multiple types, because this
266
+ is just about content injection. Of course as already said, it occurs during the compilation process and only
267
+ in the "compiled" universe. The original universe is meant to remain unmodified.
268
+
269
+ Overrides are only applied in the context of a `scenario`
270
+
271
+ ```ruby
272
+ u = UniverseCompiler.new_universe
273
+ a = EntityA.new fields: { name: :a, bar: 'Yo man', stupid: :yeah }
274
+ b = EntityA.new fields: { name: :b, extends: a }
275
+ o = UniverseCompiler.new_override fields: { name: :my_override, scenario: :test_overrides, a_new_stuff: :hey, overrides: [a, b] }
276
+ u << a << b << o
277
+
278
+ o.type # => :entity_override
279
+ v = u.compile scenario: :test_overrides
280
+ v.get_entities.map &:fields
281
+ # => [{:name=>:a,
282
+ # :bar=>"Yo man",
283
+ # :stupid=>:yeah,
284
+ # :some_data=>{},
285
+ # :a_new_stuff=>:hey},
286
+ # {:name=>:b,
287
+ # :bar=>"Yo man",
288
+ # :stupid=>:yeah,
289
+ # :some_data=>{},
290
+ # :extends=>
291
+ # #<EntityA:47368495795560 composite_key=[:some_entity, :a], @universe='Unnamed Universe - COMPILED #47368495813960'>,
292
+ # :a_new_stuff=>:hey},
293
+ # {:name=>:my_override,
294
+ # :scenario=>:test_overrides,
295
+ # :a_new_stuff=>:hey,
296
+ # :overrides=>
297
+ # [#<EntityA:47368495795560 composite_key=[:some_entity, :a], @universe='Unnamed Universe - COMPILED #47368495813960'>,
298
+ # #<EntityA:47368495725460 composite_key=[:some_entity, :b], @universe='Unnamed Universe - COMPILED #47368495813960'>]}]
299
+ #
300
+ ```
301
+ You can see there that the compiled version of `b` contains both data coming from the inheritance mechanism
302
+ as well as those coming from the override...
303
+
304
+ ## Development
305
+
306
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
307
+
308
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
309
+
310
+ ## Contributing
311
+
312
+ Bug reports and pull requests are welcome on Gitlab at https://gitlab.com/lbriais/universe_compiler. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
313
+
314
+
315
+ ## License
316
+
317
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
318
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'universe_compiler'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ require 'pry'
10
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,31 @@
1
+
2
+ module UniverseCompiler
3
+ module Entity
4
+
5
+ module AutoNamed
6
+
7
+ attr_reader :auto_named_entity_type_seed
8
+
9
+ def auto_named_entity_type(seed = nil)
10
+ @auto_named_entity_type = true
11
+ @auto_named_entity_type_seed = if seed.nil?
12
+ entity_type.to_s
13
+ else
14
+ seed
15
+ end
16
+ @entity_type_counter = 0
17
+ end
18
+
19
+ def auto_named_entity_type?
20
+ @auto_named_entity_type
21
+ end
22
+
23
+ def get_unique_name
24
+ @entity_type_counter += 1
25
+ '%s_%u' % [auto_named_entity_type_seed, @entity_type_counter]
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end