bodhi-slam 0.8.6 → 0.8.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bodhi-slam.rb +3 -3
- data/lib/bodhi-slam/factory.rb +80 -20
- data/lib/bodhi-slam/properties.rb +127 -81
- data/lib/bodhi-slam/resource.rb +296 -140
- data/lib/bodhi-slam/simulator.rb +1 -5
- data/lib/bodhi-slam/support.rb +13 -3
- data/lib/bodhi-slam/types.rb +139 -15
- data/lib/bodhi-slam/validations.rb +74 -78
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df0ac516bd1d04bc4cd3aa891949ba67998980c2
|
4
|
+
data.tar.gz: 9d300e641fd66ca7a460eb02d5a569a5549d3c62
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 267ee73450c418081f5b14d19f5accbaa2ad30ed1ebae413b11c02c2434182887ce4dc11e8ae17a24bb4ff0de14b47e17c89fdb8e6d941a5ca1f7f7ed06a27b7
|
7
|
+
data.tar.gz: bf6d08460651b649e0ca05bad80f07c299a9b62636dc049658f6695fcca88ff9114542748902507dbf936d7458293b298c4ae6fa75566bfd07c04787164ca9fd
|
data/lib/bodhi-slam.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "json"
|
2
2
|
require "time"
|
3
3
|
require 'faraday'
|
4
|
-
require '
|
4
|
+
require 'securerandom'
|
5
5
|
require 'faraday_middleware'
|
6
6
|
require 'faraday-http-cache'
|
7
7
|
require 'net/http/persistent'
|
@@ -76,7 +76,7 @@ class BodhiSlam
|
|
76
76
|
end
|
77
77
|
|
78
78
|
# Dynamically creates Ruby Classes for each type in the given +context+
|
79
|
-
#
|
79
|
+
#
|
80
80
|
# context = Bodhi::Context.new(valid_params)
|
81
81
|
# BodhiSlam.analyze(context) # => [#<Class:0x007fbff403e808 @name="TestType">, #<Class:0x007fbff403e808 @name="TestType2">, ...]
|
82
82
|
def self.analyze(context)
|
@@ -95,4 +95,4 @@ class BodhiSlam
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
end
|
98
|
-
end
|
98
|
+
end
|
data/lib/bodhi-slam/factory.rb
CHANGED
@@ -1,9 +1,18 @@
|
|
1
1
|
module Bodhi
|
2
2
|
module Factories
|
3
3
|
module ClassMethods
|
4
|
+
# Returns the Classes +Bodhi::Factory+ object
|
5
|
+
# @return [Bodhi::Factory]
|
4
6
|
def factory; @factory; end
|
7
|
+
|
8
|
+
# Define a factory generator with the given +name+ and +options+
|
9
|
+
# and append to the Classes Bodhi::Factory
|
10
|
+
# @param name [String] the name of the property
|
11
|
+
# @param options [Hash] the Bodhi::Properties
|
12
|
+
# @return [nil]
|
5
13
|
def generates(name, options)
|
6
14
|
@factory.add_generator(name.to_sym, options)
|
15
|
+
return nil
|
7
16
|
end
|
8
17
|
end
|
9
18
|
|
@@ -13,18 +22,49 @@ module Bodhi
|
|
13
22
|
end
|
14
23
|
end
|
15
24
|
|
25
|
+
# Randomize and save records to the cloud.
|
26
|
+
#
|
27
|
+
# Use the built in {Bodhi::Validator} classes to define constraints for
|
28
|
+
# randomizing records. You can also create your own lambda expressions for further
|
29
|
+
# fine grain control.
|
30
|
+
# @example Define factories
|
31
|
+
# factory = Bodhi::Factory.new(Drone)
|
32
|
+
# @example Default generators using {Bodhi::Type.properties} options
|
33
|
+
# factory.add_generator(:motor_count, type: Integer, min: 1, max: 8 )
|
34
|
+
# @example Create custom generators using lambda syntax
|
35
|
+
# factory.add_generator(:color, lambda { ["Red", "Green", "Blue", "Black"].sample } )
|
36
|
+
# @example Build a new record with randomly generated attributes
|
37
|
+
# quad_copter = factory.build(motor_count: 4)
|
38
|
+
# quad_copter # => #<Drone:0x007fbff403e808 @motor_count=4 @color="Red" >
|
39
|
+
# @example Build an array of random records
|
40
|
+
# quad_copters = factory.build_list(10, motor_count: 4)
|
41
|
+
# quad_copters # => [#<Drone:0x007fbff403e808 @motor_count=4 @color="Blue" >, ...]
|
42
|
+
# @example Build and save a randomly generated record
|
43
|
+
# quad_copter = factory.create(bodhi_context: context, motor_count: 4)
|
44
|
+
# quad_copter # => #<Drone:0x007fbff403e808 @motor_count=4 @color="Green" >
|
45
|
+
# @example Build and save an array of random records
|
46
|
+
# quad_copters = factory.create_list(10, bodhi_context: context, motor_count: 4)
|
47
|
+
# quad_copters # => [#<Drone:0x007fbff403e808 @motor_count=4 @color="Blue" >, ...]
|
16
48
|
class Factory
|
49
|
+
# The class that will be used to generate random instances
|
17
50
|
attr_reader :klass
|
51
|
+
|
52
|
+
# Hash of property names with lambda's to generate random values
|
18
53
|
attr_accessor :generators
|
19
54
|
|
55
|
+
# Initialize a new Factory using the given base class
|
56
|
+
# @param base [Class] the class you want to generate random instances for
|
20
57
|
def initialize(base)
|
21
58
|
@klass = base
|
22
59
|
@generators = Hash.new
|
23
60
|
end
|
24
61
|
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
62
|
+
# Builds a new randomly generated resource
|
63
|
+
# and accepts a options hash to override specified properties.
|
64
|
+
#
|
65
|
+
# @param options [Hash] the properties and values that should +NOT+ be randomized
|
66
|
+
# @return [Bodhi::Resource] the randomly generated resource
|
67
|
+
# @example
|
28
68
|
# Resource.factory.build # => #<Resource:0x007fbff403e808 @name="2-3lmwp^oef@245">
|
29
69
|
# Resource.factory.build(name: "test") # => #<Resource:0x007fbff403e808 @name="test">
|
30
70
|
def build(options={})
|
@@ -40,31 +80,43 @@ module Bodhi
|
|
40
80
|
object
|
41
81
|
end
|
42
82
|
|
43
|
-
#
|
44
|
-
#
|
83
|
+
# Builds an array of randomly generated resources
|
84
|
+
# and accepts a options hash to override specified properties.
|
85
|
+
#
|
86
|
+
# @param size [Integer] the amount of resources to generate
|
87
|
+
# @param options [Hash] the properties and values that should +NOT+ be randomized
|
88
|
+
# @return [Array<Bodhi::Resource>] An Array of randomly generated resources
|
89
|
+
# @example
|
45
90
|
# Resource.factory.build_list(10) # => [#<Resource:0x007fbff403e808 @name="2-3lmwp^oef@245">, #<Resource:0x007fbff403e808 @name="p7:n#$903<u1">, ...]
|
46
91
|
# Resource.factory.build_list(10, name: "test") # => [#<Resource:0x007fbff403e808 @name="test">, #<Resource:0x007fbff403e808 @name="test">, ...]
|
47
92
|
def build_list(size, options={})
|
48
93
|
size.times.collect{ build(options) }
|
49
94
|
end
|
50
95
|
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
96
|
+
# Generates a random resource and saves it to the IoT Platform
|
97
|
+
# and accepts a options hash to override specified properties.
|
98
|
+
#
|
99
|
+
# @param options [Hash] the properties and values that should +NOT+ be randomized
|
100
|
+
# @return [Bodhi::Resource] the randomly generated resource
|
101
|
+
# @example
|
102
|
+
# Resource.factory.create(bodhi_context: context) # => #<Resource:0x007fbff403e808 @name="2-3lmwp^oef@245">
|
103
|
+
# Resource.factory.create(bodhi_context: context, name: "test") # => #<Resource:0x007fbff403e808 @name="test">
|
57
104
|
def create(options={})
|
58
105
|
object = build(options)
|
59
106
|
object.save!
|
60
107
|
object
|
61
108
|
end
|
62
109
|
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
110
|
+
# Generates an array of random resources and saves them to the IoT Platform
|
111
|
+
# and accepts a options hash to override specified properties.
|
112
|
+
#
|
113
|
+
# @param size [Integer] the amount of resources to generate
|
114
|
+
# @param options [Hash] the properties and values that should +NOT+ be randomized
|
115
|
+
# @return [Array<Bodhi::Resource>] An Array of randomly generated resources
|
116
|
+
# @raise [Bodhi::ApiErrors] if any resource failed to be saved
|
117
|
+
# @example
|
118
|
+
# Resource.factory.create_list(10, bodhi_context: context) # => [#<Resource:0x007fbff403e808 @name="2-3lmwp^oef@245">, #<Resource:0x007fbff403e808 @name="p7:n#$903<u1">, ...]
|
119
|
+
# Resource.factory.create_list(10, bodhi_context: context, name: "test") # => [#<Resource:0x007fbff403e808 @name="test">, #<Resource:0x007fbff403e808 @name="test">, ...]
|
68
120
|
def create_list(size, options={})
|
69
121
|
resources = build_list(size, options)
|
70
122
|
resources.each{ |resource| resource.save! }
|
@@ -72,7 +124,11 @@ module Bodhi
|
|
72
124
|
end
|
73
125
|
|
74
126
|
# Adds a new generator to the class with the specified +name+ and +options+
|
75
|
-
#
|
127
|
+
#
|
128
|
+
# @param name [String, Symbol] the name of the property
|
129
|
+
# @param options [Hash] the Bodhi::Properties options to generate
|
130
|
+
# @return [nil]
|
131
|
+
# @example
|
76
132
|
# Resource.factory.add_generator("name", type: "String")
|
77
133
|
# Resource.factory.add_generator("test", type: "Integer", multi: true, required: true)
|
78
134
|
def add_generator(name, options)
|
@@ -81,11 +137,15 @@ module Bodhi
|
|
81
137
|
else
|
82
138
|
@generators[name.to_sym] = build_default_generator(options)
|
83
139
|
end
|
140
|
+
|
141
|
+
return nil
|
84
142
|
end
|
85
143
|
|
86
144
|
private
|
145
|
+
|
146
|
+
# @todo clean up this nasty abomination of a method!
|
87
147
|
def build_default_generator(options)
|
88
|
-
options = options.reduce({}) do |memo, (k, v)|
|
148
|
+
options = options.reduce({}) do |memo, (k, v)|
|
89
149
|
memo.merge({ Bodhi::Support.underscore(k.to_s).to_sym => v})
|
90
150
|
end
|
91
151
|
|
@@ -181,7 +241,7 @@ module Bodhi
|
|
181
241
|
# define max/min lattitude
|
182
242
|
min_lat = -90.0
|
183
243
|
max_lat = 90.0
|
184
|
-
|
244
|
+
|
185
245
|
if options[:multi]
|
186
246
|
generator = lambda do
|
187
247
|
[*0..5].sample.times.collect do
|
@@ -333,4 +393,4 @@ module Bodhi
|
|
333
393
|
end
|
334
394
|
|
335
395
|
end
|
336
|
-
end
|
396
|
+
end
|
@@ -1,118 +1,164 @@
|
|
1
1
|
module Bodhi
|
2
|
+
# This module helps turn a Ruby Object into a Form Object.
|
3
|
+
# It manages the objects properties as well as serialization to JSON
|
4
|
+
# @example
|
5
|
+
# class MyNewClass
|
6
|
+
# include Bodhi::properties
|
7
|
+
#
|
8
|
+
# property :attribute_1, type: String
|
9
|
+
# property :attribute_2, type: DateTime
|
10
|
+
# ...
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# object = MyNewClass.new(attribute_1: "Foo", attribute_2: Time.now)
|
14
|
+
# object.to_json #=> {"attribute_1":"Foo", "attribute_2": "2016-08-16T13:15:19-07:00"}
|
2
15
|
module Properties
|
3
16
|
|
17
|
+
# Default properties for ALL records on the IoT Platform
|
4
18
|
SYSTEM_PROPERTIES = [:sys_created_at, :sys_version, :sys_modified_at, :sys_modified_by,
|
5
19
|
:sys_namespace, :sys_created_by, :sys_type_version, :sys_id, :sys_embeddedType]
|
6
20
|
attr_accessor *SYSTEM_PROPERTIES
|
7
21
|
|
8
22
|
module ClassMethods
|
23
|
+
# Retuns a Hash of the Classes properties
|
24
|
+
# @return [Hash] The classes properties and options
|
9
25
|
def properties; @properties; end
|
26
|
+
|
27
|
+
# A list of all property names
|
28
|
+
# @return [Array<String>]
|
10
29
|
def property_names; @properties.keys; end
|
30
|
+
|
31
|
+
# Set a new property with the given +name+ and +options+
|
32
|
+
# @param name [String, Symbol]
|
33
|
+
# @param options [Hash]
|
34
|
+
# @return [nil]
|
35
|
+
# @example
|
36
|
+
# Resource.property("age", type: Integer, required: true, min: 18)
|
37
|
+
# Resource.property("birthday", type: DateTime, required: true)
|
38
|
+
# Resource.property(:tags, type: String, multi: true)
|
39
|
+
# Resource.property(:dogs", type: "Dog", multi: true)
|
11
40
|
def property(name, options)
|
12
41
|
attr_accessor name.to_sym
|
13
42
|
@properties[name.to_sym] = options.reduce({}) do |memo, (k, v)|
|
14
43
|
memo.merge({ Bodhi::Support.reverse_camelize(k.to_s).to_sym => v})
|
15
44
|
end
|
45
|
+
|
46
|
+
return nil
|
16
47
|
end
|
17
48
|
end
|
18
49
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
def new_record?; @sys_id.nil?; end
|
23
|
-
def each; attributes.each{ |k, v| yield(k, v) }; end
|
24
|
-
|
25
|
-
# Initializes a new instance of the class. Accepts a parameter Hash for mass assignment.
|
26
|
-
# If a parameter does not exist for the class, an UndefinedMethod error is raised.
|
27
|
-
#
|
28
|
-
# klass = Class.new do
|
29
|
-
# include Bodhi::Properties
|
30
|
-
# property :name, :email
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# object = klass.new(name: "Bob", email: "some@email.com")
|
34
|
-
# object.name #=> "Bob"
|
35
|
-
# object.email #=> "some@email.com"
|
36
|
-
def initialize(options={})
|
37
|
-
if options.is_a?(String)
|
38
|
-
options = JSON.parse(options)
|
39
|
-
end
|
50
|
+
# Wraps the sys_id property into a more Rails friendly attribute
|
51
|
+
# @return [String]
|
52
|
+
def id; @sys_id; end
|
40
53
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
property_options = self.class.properties[property]
|
45
|
-
if property_options.nil?
|
46
|
-
send("#{property}=", value)
|
47
|
-
else
|
48
|
-
send("#{property}=", Bodhi::Support.coerce(value, property_options))
|
49
|
-
end
|
50
|
-
end
|
54
|
+
# Returns +true+ if the record has been saved to the IoT Platform
|
55
|
+
# @return [Boolean]
|
56
|
+
def persisted?; !@sys_id.nil?; end
|
51
57
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
58
|
+
# Returns +true+ if the record has +NOT+ been saved to the IoT Platform
|
59
|
+
# @return [Boolean]
|
60
|
+
def new_record?; @sys_id.nil?; end
|
61
|
+
|
62
|
+
# Initializes a new instance of the class. Accepts a parameter Hash for mass assignment.
|
63
|
+
#
|
64
|
+
# @param options [Hash, JSON String]
|
65
|
+
# @example
|
66
|
+
# klass = Class.new do
|
67
|
+
# include Bodhi::Properties
|
68
|
+
# property :name, :email
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# object = klass.new(name: "Bob", email: "some@email.com")
|
72
|
+
# object.name #=> "Bob"
|
73
|
+
# object.email #=> "some@email.com"
|
74
|
+
def initialize(options={})
|
75
|
+
if options.is_a?(String)
|
76
|
+
options = JSON.parse(options)
|
56
77
|
end
|
57
78
|
|
58
|
-
#
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
value = send(property)
|
67
|
-
if value.respond_to?(:attributes)
|
68
|
-
attributes[property] = value.attributes.delete_if { |k, v| v.nil? }
|
69
|
-
elsif value.is_a?(Array) && value.first.respond_to?(:attributes)
|
70
|
-
attributes[property] = value.map(&:attributes).collect{ |item| item.delete_if { |k, v| v.nil? } }
|
71
|
-
elsif value.is_a?(Time)
|
72
|
-
attributes[property] = value.iso8601
|
73
|
-
else
|
74
|
-
attributes[property] = value
|
75
|
-
end
|
79
|
+
# Set properties defined by the +options+ parameter
|
80
|
+
#options = Bodhi::Support.symbolize_keys(options)
|
81
|
+
options.each do |property, value|
|
82
|
+
property_options = self.class.properties[property.to_sym]
|
83
|
+
if property_options.nil?
|
84
|
+
send("#{property}=", value)
|
85
|
+
else
|
86
|
+
send("#{property}=", Bodhi::Support.coerce(value, property_options))
|
76
87
|
end
|
88
|
+
end
|
77
89
|
|
78
|
-
|
79
|
-
|
90
|
+
# Set any default values
|
91
|
+
self.class.properties.select{ |k,v| !v[:default].nil? }.each do |property, property_options|
|
92
|
+
send("#{property}=", property_options[:default]) if send("#{property}").nil?
|
80
93
|
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns a Hash of the class properties and their values.
|
97
|
+
#
|
98
|
+
# @return [Hash]
|
99
|
+
# @example
|
100
|
+
# object = SomeResource.new(foo:"test", bar:12345)
|
101
|
+
# object.attributes # => { foo: "test", bar: 12345 }
|
102
|
+
def attributes
|
103
|
+
attributes = Hash.new
|
81
104
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
send("#{property}=", value)
|
93
|
-
else
|
94
|
-
send("#{property}=", Bodhi::Support.coerce(value, property_options))
|
95
|
-
end
|
105
|
+
self.class.property_names.each do |property|
|
106
|
+
value = send(property)
|
107
|
+
if value.respond_to?(:attributes)
|
108
|
+
attributes[property] = value.attributes.delete_if { |k, v| v.nil? }
|
109
|
+
elsif value.is_a?(Array) && value.first.respond_to?(:attributes)
|
110
|
+
attributes[property] = value.map(&:attributes).collect{ |item| item.delete_if { |k, v| v.nil? } }
|
111
|
+
elsif value.is_a?(Time)
|
112
|
+
attributes[property] = value.iso8601
|
113
|
+
else
|
114
|
+
attributes[property] = value
|
96
115
|
end
|
97
116
|
end
|
98
117
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
118
|
+
attributes.delete_if { |k, v| v.nil? }
|
119
|
+
attributes
|
120
|
+
end
|
121
|
+
|
122
|
+
# Updates the resource with the given attributes Hash
|
123
|
+
#
|
124
|
+
# @param properties [Hash] The properties to update
|
125
|
+
# @return [nil]
|
126
|
+
# @example
|
127
|
+
# s = SomeResource.factory.build(foo:"test", bar:12345)
|
128
|
+
# s.attributes # => { foo: "test", bar: 12345 }
|
129
|
+
# s.update_attributes(bar: 10)
|
130
|
+
# s.attributes # => { foo: "test", bar: 10 }
|
131
|
+
def update_attributes(properties)
|
132
|
+
properties.each do |property, value|
|
133
|
+
property_options = self.class.properties[property.to_sym]
|
134
|
+
if property_options.nil?
|
135
|
+
send("#{property}=", value)
|
136
|
+
else
|
137
|
+
send("#{property}=", Bodhi::Support.coerce(value, property_options))
|
138
|
+
end
|
109
139
|
end
|
140
|
+
|
141
|
+
return nil
|
142
|
+
end
|
143
|
+
|
144
|
+
# Returns all the classes properties as JSON.
|
145
|
+
# It converts any nested objects to JSON if they respond to +to_json+
|
146
|
+
#
|
147
|
+
# @param options [Hash]
|
148
|
+
# @return [String] the JSON for all properties on the object
|
149
|
+
# @example
|
150
|
+
# resource = SomeResource.new(foo:"test", bar:12345)
|
151
|
+
# embedded_resources = AnotherResource.new( test: resource )
|
152
|
+
#
|
153
|
+
# resource.to_json # => "{ 'foo':'test', 'bar':12345 }"
|
154
|
+
# embedded_resources.to_json # => "{ 'test': { 'foo':'test', 'bar':12345 } }"
|
155
|
+
def to_json(options=nil)
|
156
|
+
attributes.to_json
|
110
157
|
end
|
111
158
|
|
112
159
|
def self.included(base)
|
113
160
|
base.extend(ClassMethods)
|
114
|
-
base.include(InstanceMethods, Enumerable)
|
115
161
|
base.instance_variable_set(:@properties, Hash.new)
|
116
162
|
end
|
117
163
|
end
|
118
|
-
end
|
164
|
+
end
|