cloud-templates 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +29 -0
- data/.simplecov +6 -0
- data/Gemfile +2 -0
- data/LICENSE +201 -0
- data/NOTICE +13 -0
- data/README.md +124 -0
- data/Rakefile +27 -0
- data/cloud-templates.gemspec +27 -0
- data/examples/lib/user_directory/artifacts/catalogized.rb +11 -0
- data/examples/lib/user_directory/artifacts/group.rb +37 -0
- data/examples/lib/user_directory/artifacts/ided.rb +11 -0
- data/examples/lib/user_directory/artifacts/organization.rb +17 -0
- data/examples/lib/user_directory/artifacts/pathed.rb +22 -0
- data/examples/lib/user_directory/artifacts/person.rb +20 -0
- data/examples/lib/user_directory/artifacts/team.rb +31 -0
- data/examples/lib/user_directory/artifacts/unit.rb +24 -0
- data/examples/lib/user_directory/artifacts/user.rb +29 -0
- data/examples/lib/user_directory/render/etc/artifact_view.rb +15 -0
- data/examples/lib/user_directory/render/etc/composite_view.rb +26 -0
- data/examples/lib/user_directory/render/etc/group_view.rb +23 -0
- data/examples/lib/user_directory/render/etc/person_view.rb +19 -0
- data/examples/lib/user_directory/render/etc/registry.rb +33 -0
- data/examples/lib/user_directory/render/etc/user_view.rb +35 -0
- data/examples/lib/user_directory/render/etc.rb +3 -0
- data/examples/lib/user_directory/render/ldap/artifact_view.rb +27 -0
- data/examples/lib/user_directory/render/ldap/composite_view.rb +32 -0
- data/examples/lib/user_directory/render/ldap/group_view.rb +28 -0
- data/examples/lib/user_directory/render/ldap/organization_view.rb +26 -0
- data/examples/lib/user_directory/render/ldap/person_view.rb +39 -0
- data/examples/lib/user_directory/render/ldap/registry.rb +16 -0
- data/examples/lib/user_directory/render/ldap/unit_view.rb +26 -0
- data/examples/lib/user_directory/render/ldap/user_view.rb +39 -0
- data/examples/lib/user_directory/render/ldap.rb +3 -0
- data/examples/lib/user_directory/utils.rb +18 -0
- data/examples/lib/user_directory.rb +23 -0
- data/examples/lib_path.rb +2 -0
- data/examples/spec/spec_helper.rb +1 -0
- data/examples/spec/user_directory_spec.rb +568 -0
- data/lib/aws/templates/artifact.rb +140 -0
- data/lib/aws/templates/composite.rb +178 -0
- data/lib/aws/templates/exceptions.rb +221 -0
- data/lib/aws/templates/render/registry.rb +60 -0
- data/lib/aws/templates/render/utils/base_type_views.rb +131 -0
- data/lib/aws/templates/render/view.rb +127 -0
- data/lib/aws/templates/render.rb +72 -0
- data/lib/aws/templates/utils/artifact_storage.rb +141 -0
- data/lib/aws/templates/utils/contextualized/filters.rb +437 -0
- data/lib/aws/templates/utils/contextualized/hash.rb +13 -0
- data/lib/aws/templates/utils/contextualized/nil.rb +13 -0
- data/lib/aws/templates/utils/contextualized/proc.rb +13 -0
- data/lib/aws/templates/utils/contextualized.rb +113 -0
- data/lib/aws/templates/utils/default.rb +185 -0
- data/lib/aws/templates/utils/dependency/enumerable.rb +13 -0
- data/lib/aws/templates/utils/dependency/object.rb +46 -0
- data/lib/aws/templates/utils/dependency.rb +121 -0
- data/lib/aws/templates/utils/dependent.rb +28 -0
- data/lib/aws/templates/utils/inheritable.rb +52 -0
- data/lib/aws/templates/utils/late_bound.rb +89 -0
- data/lib/aws/templates/utils/memoized.rb +27 -0
- data/lib/aws/templates/utils/named.rb +19 -0
- data/lib/aws/templates/utils/options.rb +279 -0
- data/lib/aws/templates/utils/parametrized/constraints.rb +423 -0
- data/lib/aws/templates/utils/parametrized/getters.rb +293 -0
- data/lib/aws/templates/utils/parametrized/guarded.rb +32 -0
- data/lib/aws/templates/utils/parametrized/mapper.rb +73 -0
- data/lib/aws/templates/utils/parametrized/nested.rb +72 -0
- data/lib/aws/templates/utils/parametrized/transformations.rb +660 -0
- data/lib/aws/templates/utils/parametrized.rb +240 -0
- data/lib/aws/templates/utils.rb +219 -0
- data/lib/aws/templates.rb +16 -0
- data/spec/aws/templates/artifact_spec.rb +161 -0
- data/spec/aws/templates/composite_spec.rb +361 -0
- data/spec/aws/templates/render/utils/base_type_views_spec.rb +104 -0
- data/spec/aws/templates/render_spec.rb +62 -0
- data/spec/aws/templates/utils/as_named_spec.rb +31 -0
- data/spec/aws/templates/utils/contextualized/filters_spec.rb +108 -0
- data/spec/aws/templates/utils/contextualized_spec.rb +115 -0
- data/spec/aws/templates/utils/late_bound_spec.rb +52 -0
- data/spec/aws/templates/utils/options_spec.rb +67 -0
- data/spec/aws/templates/utils/parametrized/constraint_spec.rb +175 -0
- data/spec/aws/templates/utils/parametrized/getters_spec.rb +139 -0
- data/spec/aws/templates/utils/parametrized/transformation_spec.rb +314 -0
- data/spec/aws/templates/utils/parametrized_spec.rb +241 -0
- data/spec/spec_helper.rb +6 -0
- metadata +244 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'aws/templates/render'
|
2
|
+
require 'aws/templates/render/view'
|
3
|
+
require 'aws/templates/utils'
|
4
|
+
require 'aws/templates/utils/dependency'
|
5
|
+
require 'aws/templates/utils/options'
|
6
|
+
|
7
|
+
module Aws
|
8
|
+
module Templates
|
9
|
+
module Render
|
10
|
+
module Utils
|
11
|
+
##
|
12
|
+
# Utility views
|
13
|
+
#
|
14
|
+
# A collection of handful utility views which know how to flexibly render values into
|
15
|
+
# specific types.
|
16
|
+
module BaseTypeViews
|
17
|
+
include Render
|
18
|
+
|
19
|
+
##
|
20
|
+
# Pass-through render
|
21
|
+
class AsIs < BasicView
|
22
|
+
def to_rendered
|
23
|
+
instance.object
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Convert to string
|
29
|
+
class ToString < BasicView
|
30
|
+
def to_rendered
|
31
|
+
instance.to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Convert to array
|
37
|
+
#
|
38
|
+
# Converts value to array and iteratively renders every element in it.
|
39
|
+
class ToArray < BasicView
|
40
|
+
def to_rendered
|
41
|
+
instance
|
42
|
+
.to_a
|
43
|
+
.map { |element| render.view_for(element, parameters).to_rendered }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Convert to hash
|
49
|
+
#
|
50
|
+
# Converts value to hash and iteratively renders each key and value in it.
|
51
|
+
class ToHash < BasicView
|
52
|
+
def to_rendered
|
53
|
+
_from(instance).map { |k, v| [_to_rendered(k), _to_rendered(v)] }.to_h
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def _from(obj)
|
59
|
+
if obj.respond_to?(:to_h)
|
60
|
+
instance.to_h
|
61
|
+
else
|
62
|
+
instance.to_hash
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def _to_rendered(obj)
|
67
|
+
render.view_for(obj, parameters).to_rendered
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Convert to float
|
73
|
+
class ToFloat < BasicView
|
74
|
+
def to_rendered
|
75
|
+
instance.to_f
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Convert to integer
|
81
|
+
class ToInteger < BasicView
|
82
|
+
def to_rendered
|
83
|
+
instance.to_i
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Convert to boolean
|
89
|
+
class ToBoolean < BasicView
|
90
|
+
def to_rendered
|
91
|
+
!instance.to_s.casecmp('false').zero?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
DEFAULT_RENDERING_MAP = {
|
96
|
+
::String => AsIs,
|
97
|
+
::Float => AsIs,
|
98
|
+
::Integer => AsIs,
|
99
|
+
::TrueClass => AsIs,
|
100
|
+
::FalseClass => AsIs,
|
101
|
+
::NilClass => AsIs,
|
102
|
+
::Symbol => AsIs,
|
103
|
+
Templates::Utils::Dependency => AsIs,
|
104
|
+
::Array => ToArray,
|
105
|
+
::Hash => ToHash,
|
106
|
+
Templates::Utils::Options => ToHash
|
107
|
+
}.freeze
|
108
|
+
|
109
|
+
##
|
110
|
+
# Set all default views
|
111
|
+
#
|
112
|
+
# Set all default views for defined types. Views module class definitions are used
|
113
|
+
def initialize_base_type_views
|
114
|
+
DEFAULT_RENDERING_MAP.each_pair { |klass, view| define_view(klass, view) }
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Set default views for specific classes
|
119
|
+
#
|
120
|
+
# Set default views only for passed types.
|
121
|
+
def initialize_base_type_views_for(*classes)
|
122
|
+
classes.each do |k|
|
123
|
+
raise "Can't find default view for class #{k}" unless DEFAULT_RENDERING_MAP.key?(k)
|
124
|
+
define_view(k, DEFAULT_RENDERING_MAP[k])
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Aws
|
2
|
+
module Templates
|
3
|
+
module Render
|
4
|
+
##
|
5
|
+
# Basic render view
|
6
|
+
#
|
7
|
+
# Views are classes encapsulating functionality of transforming
|
8
|
+
# artifacts into domain-specific output. For instance, the same
|
9
|
+
# LDAP record can be transformed into JSON description or LDIF definition.
|
10
|
+
# Views can be attached to ancestors of an artifact and it expected
|
11
|
+
# that the library will look-up the closest ancestor having view attached
|
12
|
+
# if the render is invoked on a child.
|
13
|
+
#
|
14
|
+
# Each view is attached to a registry object which stores correspondence
|
15
|
+
# between artifact classes and their views, and optionally to an artifact.
|
16
|
+
# A view is registered in a registry only when it is attached to an artifact.
|
17
|
+
# Views depend on artifacts but artifacts are not aware of views.
|
18
|
+
# As the extreme case, a sole view can be attached to Artifact
|
19
|
+
# if you have universal way to render your domain objects.
|
20
|
+
#
|
21
|
+
# Views are regular Ruby classes and all assumptions made about
|
22
|
+
# polymorphism, inheritance and incapsulation are true for them.
|
23
|
+
#
|
24
|
+
# View class itself is an abstract class which can't be instantiated
|
25
|
+
# directly.
|
26
|
+
class BasicView
|
27
|
+
##
|
28
|
+
# Render accessor
|
29
|
+
#
|
30
|
+
# Returns either render of this view class or render of any ancestor.
|
31
|
+
def self.render
|
32
|
+
@render || superclass.render
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Register the view class in a render
|
37
|
+
#
|
38
|
+
# Registers the view class in the render
|
39
|
+
# * +r+ - render registrar
|
40
|
+
def self.register_in(r)
|
41
|
+
@render = r
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Link the view class to the artifact class
|
47
|
+
#
|
48
|
+
# Registers the link in the render object of the view class.
|
49
|
+
def self.artifact(artifact_class)
|
50
|
+
render.register(artifact_class, self)
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Artifact instance view object is attached to
|
56
|
+
attr_reader :instance
|
57
|
+
|
58
|
+
##
|
59
|
+
# Assigned view parameters
|
60
|
+
attr_reader :parameters
|
61
|
+
|
62
|
+
##
|
63
|
+
# Execute in the instance context
|
64
|
+
#
|
65
|
+
# Executed passed block in the context of the instance being rendered. It helps against
|
66
|
+
# putting too much instance method accesses in long blocks. Returns the value returned by
|
67
|
+
# the block.
|
68
|
+
def in_instance(*args, &blk)
|
69
|
+
instance.instance_exec(*args, &blk)
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Create view instance and link it to the artifact instance
|
74
|
+
def initialize(obj, params = nil)
|
75
|
+
@instance = obj
|
76
|
+
@parameters = params
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Alias for class method render
|
81
|
+
def render
|
82
|
+
self.class.render
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Render the object
|
87
|
+
#
|
88
|
+
# Renders passed object with the view default render
|
89
|
+
def rendered_for(obj)
|
90
|
+
render.view_for(obj, parameters).to_rendered
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Render the instance of the artifact
|
95
|
+
#
|
96
|
+
# The method should be overriden and return rendered form of the attached instance
|
97
|
+
def to_rendered
|
98
|
+
raise NotImplementedError.new('The method should be overriden')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# Render view
|
104
|
+
#
|
105
|
+
# The class introduces additional stage called "prepare" where you can put prepared view
|
106
|
+
# which will be additionally recursively rendered. Useful for complex views containing values
|
107
|
+
# needed additional rendering so you don't need to invoke rendered_for.
|
108
|
+
class View < BasicView
|
109
|
+
##
|
110
|
+
# Render the instance of the artifact
|
111
|
+
#
|
112
|
+
# The method renders value returned by prepare
|
113
|
+
def to_rendered
|
114
|
+
rendered_for(prepare)
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Prepare value for rendering
|
119
|
+
#
|
120
|
+
# Should be overriden. Should return a value which is to be passed for final rendering.
|
121
|
+
def prepare
|
122
|
+
raise NotImplementedError.new('The method should be overriden')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'aws/templates/exceptions'
|
2
|
+
require 'aws/templates/render/registry'
|
3
|
+
require 'aws/templates/render/view'
|
4
|
+
|
5
|
+
module Aws
|
6
|
+
module Templates
|
7
|
+
##
|
8
|
+
# View layer of the MVC pattern
|
9
|
+
#
|
10
|
+
# View layer provides means of defining "views" of your artifacts
|
11
|
+
# to define different ways of rendering the object hierarchies you
|
12
|
+
# create to end representation.
|
13
|
+
#
|
14
|
+
# The module also contains a few mixin methods to simplify creation
|
15
|
+
# of "renders" - collections of views defining the same domain
|
16
|
+
# representation. For instance JSON, LDIF, Wiki could be such
|
17
|
+
# final destinations.
|
18
|
+
#
|
19
|
+
# Renders could be classes or modules. Modules work best if no
|
20
|
+
# customization is needed and you want a singleton.
|
21
|
+
#
|
22
|
+
# === Example
|
23
|
+
#
|
24
|
+
# class Wiki
|
25
|
+
# include Aws::Templates::Render
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# module JSON
|
29
|
+
# extend Aws::Templates::Render
|
30
|
+
# end
|
31
|
+
module Render
|
32
|
+
##
|
33
|
+
# Registry accessor
|
34
|
+
#
|
35
|
+
# All views and corresponding artifacts in a render are stored
|
36
|
+
# in a registry.
|
37
|
+
def registry
|
38
|
+
@registry ||= Registry.new
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Proxy for Registry register method
|
43
|
+
def register(*args)
|
44
|
+
registry.register(*args)
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Proxy for Registry can_render? method
|
49
|
+
def can_render?(*args)
|
50
|
+
registry.can_render?(*args)
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Proxy for Registry view_for method
|
55
|
+
def view_for(*args)
|
56
|
+
registry.view_for(*args)
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Define view for artifact
|
61
|
+
#
|
62
|
+
# Another way to define views for artifacts. Creates anonymous class and attaches as the view
|
63
|
+
# to the specified artifact
|
64
|
+
def define_view(artifact_class, view = nil, &blk)
|
65
|
+
Class
|
66
|
+
.new(view || Aws::Templates::Render::BasicView, &blk)
|
67
|
+
.register_in(self)
|
68
|
+
.artifact(artifact_class)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'aws/templates/artifact'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Aws
|
5
|
+
module Templates
|
6
|
+
module Utils
|
7
|
+
##
|
8
|
+
# Arifact storage
|
9
|
+
#
|
10
|
+
# It mimics behavior of Hash providing additional ability to search
|
11
|
+
# through elements checking for different types of matches:
|
12
|
+
# * labels
|
13
|
+
# * classes
|
14
|
+
# * parameters
|
15
|
+
# It is also able to perform recursive deep search and de-duplication of artifact objects
|
16
|
+
class ArtifactStorage < Hash
|
17
|
+
include Enumerable
|
18
|
+
|
19
|
+
##
|
20
|
+
# Find artifacts by criteria
|
21
|
+
#
|
22
|
+
# The method allows flexible introspection of the artifacts
|
23
|
+
# enclosed into the storage.
|
24
|
+
#
|
25
|
+
# * +search_params+ - map of search parameters:
|
26
|
+
# ** +recursive+ - if true, search will be performed recusrsively
|
27
|
+
# in nested composites
|
28
|
+
# ** +label+ - search for artifacts which have the label
|
29
|
+
# ** +parameters+ - search for artifacts which have specified
|
30
|
+
# parameters values; it's a multi-level map so
|
31
|
+
# you can check for nested values also
|
32
|
+
def search(search_params = {})
|
33
|
+
found = filter_artifacts(search_params)
|
34
|
+
|
35
|
+
if search_params[:recursive]
|
36
|
+
values
|
37
|
+
.select { |object| object.respond_to?(:search) }
|
38
|
+
.each { |object| found.concat(object.search(search_params)) }
|
39
|
+
end
|
40
|
+
|
41
|
+
found
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Artifacts list
|
46
|
+
def artifacts
|
47
|
+
@set.to_a
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Artifacts' labels list
|
52
|
+
def labels
|
53
|
+
@map.keys
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# If the label is present
|
58
|
+
def label?(l)
|
59
|
+
@map.key?(l)
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Extract object by label
|
64
|
+
def [](k)
|
65
|
+
@map[k]
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Associate label to the object
|
70
|
+
def []=(k, v)
|
71
|
+
raise 'nil artifacts are not supported' if v.nil?
|
72
|
+
@set << v unless @set.include?(v)
|
73
|
+
@map[k] = v
|
74
|
+
end
|
75
|
+
|
76
|
+
alias values artifacts
|
77
|
+
alias keys labels
|
78
|
+
alias key? label?
|
79
|
+
alias include? label?
|
80
|
+
|
81
|
+
def each(&blk)
|
82
|
+
@map.each(&blk)
|
83
|
+
end
|
84
|
+
|
85
|
+
def each_pair(&blk)
|
86
|
+
@map.each_pair(&blk)
|
87
|
+
end
|
88
|
+
|
89
|
+
def map(&blk)
|
90
|
+
@map.map(&blk)
|
91
|
+
end
|
92
|
+
|
93
|
+
def select(&blk)
|
94
|
+
@map.select(&blk)
|
95
|
+
end
|
96
|
+
|
97
|
+
def reject(&blk)
|
98
|
+
@map.reject(&blk)
|
99
|
+
end
|
100
|
+
|
101
|
+
def initialize
|
102
|
+
@map = {}
|
103
|
+
@set = Set.new
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def filter_artifacts(search_params)
|
109
|
+
found = filter_by_label(search_params[:label])
|
110
|
+
|
111
|
+
klass = search_params[:klass]
|
112
|
+
params_match = search_params[:parameters]
|
113
|
+
|
114
|
+
found = found.select { |object| object.is_a?(klass) } if klass
|
115
|
+
found = found.select { |object| check_parameters(object, params_match) } if params_match
|
116
|
+
|
117
|
+
found
|
118
|
+
end
|
119
|
+
|
120
|
+
def filter_by_label(label)
|
121
|
+
return values if label.nil?
|
122
|
+
return [] unless key?(label)
|
123
|
+
|
124
|
+
[self[label]]
|
125
|
+
end
|
126
|
+
|
127
|
+
def check_parameters(object, params)
|
128
|
+
params.all? do |name, value|
|
129
|
+
if object.respond_to?(name)
|
130
|
+
if value.respond_to?(:to_hash)
|
131
|
+
check_parameters(object.send(name), value.to_hash)
|
132
|
+
else
|
133
|
+
object.send(name) == value
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|