windoo 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES.md +9 -0
- data/LICENSE.txt +177 -0
- data/README.md +222 -0
- data/lib/windoo/base_classes/array_manager.rb +335 -0
- data/lib/windoo/base_classes/criteria_manager.rb +327 -0
- data/lib/windoo/base_classes/criterion.rb +226 -0
- data/lib/windoo/base_classes/json_object.rb +472 -0
- data/lib/windoo/configuration.rb +221 -0
- data/lib/windoo/connection/actions.rb +152 -0
- data/lib/windoo/connection/attributes.rb +156 -0
- data/lib/windoo/connection/connect.rb +402 -0
- data/lib/windoo/connection/constants.rb +55 -0
- data/lib/windoo/connection/token.rb +489 -0
- data/lib/windoo/connection.rb +92 -0
- data/lib/windoo/converters.rb +31 -0
- data/lib/windoo/exceptions.rb +34 -0
- data/lib/windoo/mixins/api_collection.rb +408 -0
- data/lib/windoo/mixins/constants.rb +43 -0
- data/lib/windoo/mixins/default_connection.rb +75 -0
- data/lib/windoo/mixins/immutable.rb +34 -0
- data/lib/windoo/mixins/loading.rb +38 -0
- data/lib/windoo/mixins/patch/component.rb +102 -0
- data/lib/windoo/mixins/software_title/extension_attribute.rb +106 -0
- data/lib/windoo/mixins/utility.rb +23 -0
- data/lib/windoo/objects/capability.rb +82 -0
- data/lib/windoo/objects/capability_manager.rb +52 -0
- data/lib/windoo/objects/component.rb +99 -0
- data/lib/windoo/objects/component_criteria_manager.rb +26 -0
- data/lib/windoo/objects/component_criterion.rb +66 -0
- data/lib/windoo/objects/extension_attribute.rb +149 -0
- data/lib/windoo/objects/kill_app.rb +92 -0
- data/lib/windoo/objects/kill_app_manager.rb +89 -0
- data/lib/windoo/objects/patch.rb +235 -0
- data/lib/windoo/objects/patch_manager.rb +240 -0
- data/lib/windoo/objects/requirement.rb +85 -0
- data/lib/windoo/objects/requirement_manager.rb +52 -0
- data/lib/windoo/objects/software_title.rb +407 -0
- data/lib/windoo/validate.rb +548 -0
- data/lib/windoo/version.rb +15 -0
- data/lib/windoo/zeitwerk_config.rb +158 -0
- data/lib/windoo.rb +56 -0
- metadata +141 -0
@@ -0,0 +1,226 @@
|
|
1
|
+
# Copyright 2025 Pixar
|
2
|
+
#
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
4
|
+
# at the root of this project.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
|
8
|
+
# main module
|
9
|
+
module Windoo
|
10
|
+
|
11
|
+
module BaseClasses
|
12
|
+
|
13
|
+
# The base class for dealing with criteria in Software Titles.
|
14
|
+
#
|
15
|
+
# WARNING: CRITERIA ARE IMMUTABLE. See below for how to deal
|
16
|
+
# with this
|
17
|
+
#
|
18
|
+
# Criteria are individual comparisons or 'filter rules' used to
|
19
|
+
# identify matching computers, much as they are used for Jamf Smart
|
20
|
+
# Groups or Advanced Searches.
|
21
|
+
#
|
22
|
+
# For example, a single criterion might specify all computers where
|
23
|
+
# the app 'FooBar.app' is installed. Another might specify that
|
24
|
+
# FooBar.app is version 12.3.6, or that the OS is Big Sur or higher.
|
25
|
+
#
|
26
|
+
# In SoftwareTitles, criteria are used in three places:
|
27
|
+
#
|
28
|
+
# - As the 'requirements' of a Software Title.
|
29
|
+
# Each requrement is one criterion, and the Array of them
|
30
|
+
# define which computers have any version of the title
|
31
|
+
# installed. Access to the Array is handled via the
|
32
|
+
# Windoo::RequirementManager class.
|
33
|
+
#
|
34
|
+
# - As the criteria of the sole 'component' of a Patch.
|
35
|
+
# A Patch's 'components' is an Array of one item (for historical
|
36
|
+
# reasons apparently). That component contains an Array of
|
37
|
+
# criteria that define which computers have _that specific_
|
38
|
+
# version of the Patch's Title installed. Access to the Array is
|
39
|
+
# handled via the Windoo::ComponentCriteriaManager class.
|
40
|
+
#
|
41
|
+
# - As the 'capabilities' of a Patch.
|
42
|
+
# Each capability is one criterion, and the Array of them
|
43
|
+
# define which computers are capable of running, and thus
|
44
|
+
# allowed to install, this Patch. Access to the Array is handled
|
45
|
+
# via the Windoo::CapabilitytManager class.
|
46
|
+
#
|
47
|
+
# This class is the superclass of the individual types of criteria
|
48
|
+
# used in the Title Editor. For example Windoo::Requirement is a
|
49
|
+
# subclass of this class.
|
50
|
+
#
|
51
|
+
# Criteria always come in groups (perhaps a group of one) and are
|
52
|
+
# stored in Arrays. However, the arrays are not directly accessible,
|
53
|
+
# but are managed by subclasses of Windoo::CriteriaManager. For
|
54
|
+
# example, the Windoo::Requirement objects of a SoftwareTitle are stored
|
55
|
+
# in an instance of Windoo::RequirementManager.
|
56
|
+
#
|
57
|
+
# These 'managers' provide methods for adding, replacing, moving,
|
58
|
+
# and deleting the individual criteria in the array, and maintain
|
59
|
+
# consistency between the local array and the actual objects stored
|
60
|
+
# on the server.
|
61
|
+
#
|
62
|
+
# CRITERIA ARE IMMUTABLE:
|
63
|
+
#
|
64
|
+
# Criteria are immutable once created, mostly because to modify any of the
|
65
|
+
# primary values of one (name, operator, & value), you have to modify them
|
66
|
+
# all at once or you end up in a chicken/egg situation where the server will
|
67
|
+
# complain of invalid values, which can't easily be worked around when
|
68
|
+
# updating the values individually.
|
69
|
+
#
|
70
|
+
# Instead of modifying one, delete it and replace it with a new one in the
|
71
|
+
# same position in the array. There's a convenience method for this in the
|
72
|
+
# CriteriaManager called #replace_criterion(id)
|
73
|
+
#
|
74
|
+
# When creating criteria using CriteriaManager#add_criterion, they area added
|
75
|
+
# to the end of the array by default, but you can specify the position using the
|
76
|
+
# absoluteOrderId value. You can also move the position of a criterion in the
|
77
|
+
# array using CriteriaManager#update_criterion method and passing in the new
|
78
|
+
# absoluteOrderId value.
|
79
|
+
#
|
80
|
+
class Criterion < Windoo::BaseClasses::JSONObject
|
81
|
+
|
82
|
+
# Mixins
|
83
|
+
#####################
|
84
|
+
|
85
|
+
extend Windoo::Mixins::Immutable
|
86
|
+
|
87
|
+
# Constants
|
88
|
+
#####################
|
89
|
+
|
90
|
+
# The authoritative list of available types can be read from the API
|
91
|
+
# at GET 'valuelists/criteria/types', or also via
|
92
|
+
# Windoo::BaseClasses::CriteriaManager.available_types
|
93
|
+
|
94
|
+
TYPE_RECON = 'recon'
|
95
|
+
TYPE_EA = 'extensionAttribute'
|
96
|
+
|
97
|
+
TYPES = [TYPE_RECON, TYPE_EA].freeze
|
98
|
+
|
99
|
+
# These attributes must be updated together for Criteria objects
|
100
|
+
ATTRIBUTES_TO_UPDATE_TOGETHER = %i[name operator value].freeze
|
101
|
+
|
102
|
+
# Attributes
|
103
|
+
######################
|
104
|
+
|
105
|
+
JSON_ATTRIBUTES = {
|
106
|
+
|
107
|
+
# @!attribute absoluteOrderId
|
108
|
+
# @return [Integer] The zero-based position of this requirement among
|
109
|
+
# all those used by the title. Should be identical to the Array index
|
110
|
+
# of this requirement in the #requirements attribute of the SoftwareTitle
|
111
|
+
# instance that uses this requirement
|
112
|
+
absoluteOrderId: {
|
113
|
+
class: :Integer
|
114
|
+
},
|
115
|
+
|
116
|
+
# @!attribute and_or
|
117
|
+
# @return [Symbol] Either :and or :or. This indicates how this criterion is
|
118
|
+
# joined to the previous one in a chain of boolean logic.
|
119
|
+
#
|
120
|
+
# NOTE: In the Title Editor JSON data, this key for this value is the
|
121
|
+
# word "and" and its value is a boolean: if false, the joiner is "or".
|
122
|
+
# However, because "and" is a reserved word in ruby, we convert that
|
123
|
+
# value into this one during initialization, and back when sending
|
124
|
+
# data to the Title Editor.
|
125
|
+
and_or: {
|
126
|
+
class: :Symbol
|
127
|
+
},
|
128
|
+
|
129
|
+
# @!attribute name
|
130
|
+
# @return [String] The name of the criteria to search in this requirement.
|
131
|
+
# See the API resource GET 'valuelists/criteria/names'
|
132
|
+
name: {
|
133
|
+
class: :String,
|
134
|
+
required: true
|
135
|
+
},
|
136
|
+
|
137
|
+
# @!attribute operator
|
138
|
+
# @return [String] The criteria operator to apply to the criteria name
|
139
|
+
# See the API resource POST 'valuelists/criteria/names', {name: 'Criteria Name'}
|
140
|
+
operator: {
|
141
|
+
class: :String,
|
142
|
+
required: true
|
143
|
+
},
|
144
|
+
|
145
|
+
# @!attribute value
|
146
|
+
# @return [Object] The the value to apply with the operator to the named criteria
|
147
|
+
# We can't specify the class of the value, because it might be a String, Integer, Time, or
|
148
|
+
# something else.
|
149
|
+
value: {
|
150
|
+
class: :Object
|
151
|
+
},
|
152
|
+
|
153
|
+
# @!attribute type
|
154
|
+
# @return [String] What type of criteria is the named one?
|
155
|
+
# Must be one of the values in TYPES
|
156
|
+
type: {
|
157
|
+
class: :String,
|
158
|
+
required: true
|
159
|
+
}
|
160
|
+
}.freeze
|
161
|
+
|
162
|
+
# Constructor
|
163
|
+
######################
|
164
|
+
def initialize(**init_data)
|
165
|
+
super
|
166
|
+
# if #super didn't set @and_or, set it now
|
167
|
+
return unless @and_or.nil?
|
168
|
+
|
169
|
+
@and_or = @init_data[:and] == false ? :or : :and
|
170
|
+
end
|
171
|
+
|
172
|
+
# Public Instance Methods
|
173
|
+
################################
|
174
|
+
|
175
|
+
# Override handle @and_or before creating
|
176
|
+
#
|
177
|
+
def to_api
|
178
|
+
api_data = super
|
179
|
+
api_data[:and] = (@and_or == :and)
|
180
|
+
api_data.delete :and_or
|
181
|
+
api_data
|
182
|
+
end
|
183
|
+
|
184
|
+
# Allow array managers to change the absoluteOrderId.
|
185
|
+
#
|
186
|
+
# @todo Only allow this to be called from a CriteriaManager.
|
187
|
+
#
|
188
|
+
# @param new_index [Integer] The new, zero-based index for this
|
189
|
+
# criterion.
|
190
|
+
#
|
191
|
+
# @return [Integer] the id of the updated criterion
|
192
|
+
#
|
193
|
+
def absoluteOrderId=(new_index)
|
194
|
+
new_value = validate_attr :absoluteOrderId, new_index
|
195
|
+
return if new_value == @absoluteOrderId
|
196
|
+
|
197
|
+
update_on_server :absoluteOrderId, new_value
|
198
|
+
@absoluteOrderId = new_value
|
199
|
+
end
|
200
|
+
|
201
|
+
# Update the local absoluteOrderId without updating it on
|
202
|
+
# the server.
|
203
|
+
#
|
204
|
+
# Why??
|
205
|
+
#
|
206
|
+
# Because changing the value on the server for one criterion
|
207
|
+
# using #absoluteOrderId= will automatically change it on the
|
208
|
+
# server for all the others.
|
209
|
+
#
|
210
|
+
# After changing one on the server and updating that one in the
|
211
|
+
# local array, the CriteriaManager will use this, without
|
212
|
+
# updating the server, to change the value for all others in the
|
213
|
+
# array to match their array index.
|
214
|
+
#
|
215
|
+
# @todo Only allow this to be called from a CriteriaManager.
|
216
|
+
#
|
217
|
+
# @return [void]
|
218
|
+
def local_absoluteOrderId=(new_index)
|
219
|
+
@absoluteOrderId = new_index
|
220
|
+
end
|
221
|
+
|
222
|
+
end # class Criterion
|
223
|
+
|
224
|
+
end # module BaseClasses
|
225
|
+
|
226
|
+
end # module Windoo
|
@@ -0,0 +1,472 @@
|
|
1
|
+
# Copyright 2025 Pixar
|
2
|
+
#
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
4
|
+
# at the root of this project.
|
5
|
+
#
|
6
|
+
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
# main module
|
10
|
+
module Windoo
|
11
|
+
|
12
|
+
module BaseClasses
|
13
|
+
|
14
|
+
# The base class for objects that are instantiated from
|
15
|
+
# a JSON Hash
|
16
|
+
class JSONObject
|
17
|
+
|
18
|
+
# Constants
|
19
|
+
######################
|
20
|
+
|
21
|
+
# When using prettyprint, don't spit out these instance variables.
|
22
|
+
PP_OMITTED_INST_VARS = %i[@init_data @container @softwareTitle].freeze
|
23
|
+
|
24
|
+
# Attributes
|
25
|
+
######################
|
26
|
+
|
27
|
+
# @return [Hash] The raw JSON data this object was instantiated with
|
28
|
+
attr_reader :init_data
|
29
|
+
|
30
|
+
# Public Class Methods
|
31
|
+
######################
|
32
|
+
|
33
|
+
# by default, instances of subclasses are mutable
|
34
|
+
# as a whole (even if some attributes are readonly)
|
35
|
+
# To make them immutable, they should extend
|
36
|
+
# Windoo::Mixins::Immutable, which overrides
|
37
|
+
# this method
|
38
|
+
def self.mutable?
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
# The merged JSON_ATTRIBUTES Hashes of
|
43
|
+
# any subclass of JSONObject including
|
44
|
+
# all ancestors up to JSONObject itself
|
45
|
+
#
|
46
|
+
# @return [Hash{Symbol => Hash}]
|
47
|
+
####
|
48
|
+
def self.json_attributes
|
49
|
+
return {} if self == Windoo::BaseClasses::JSONObject
|
50
|
+
return @json_attributes if @json_attributes
|
51
|
+
|
52
|
+
@json_attributes = defined?(self::JSON_ATTRIBUTES) ? self::JSON_ATTRIBUTES.dup : {}
|
53
|
+
@json_attributes.merge! superclass.json_attributes if superclass.respond_to?(:json_attributes)
|
54
|
+
@json_attributes
|
55
|
+
end
|
56
|
+
|
57
|
+
# The attributes that are required to have values.
|
58
|
+
# These must be passed in when calling .create, and must
|
59
|
+
# exist in the instance when calling #save
|
60
|
+
#
|
61
|
+
# @return [Array<Symbol>]
|
62
|
+
####
|
63
|
+
def self.required_attributes
|
64
|
+
@required_attributes ||= json_attributes.select { |_key, deets| deets[:required] }.keys
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Array<Symbol>] the available identifier keys for objects that have them
|
68
|
+
def self.ident_keys
|
69
|
+
return @ident_keys if @ident_keys
|
70
|
+
|
71
|
+
@ident_keys = []
|
72
|
+
|
73
|
+
json_attributes.each do |key, deets|
|
74
|
+
next unless deets[:identifier]
|
75
|
+
|
76
|
+
@primary_id_key = key if deets[:identifier] == :primary
|
77
|
+
@ident_keys << key
|
78
|
+
end
|
79
|
+
|
80
|
+
@ident_keys
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [Symbol] the key of the primary identifier, if there is one
|
84
|
+
def self.primary_id_key
|
85
|
+
return @primary_id_key if @primary_id_key
|
86
|
+
|
87
|
+
# this method sets @primary_id_key as it loops through json_attributes
|
88
|
+
ident_keys
|
89
|
+
@primary_id_key
|
90
|
+
end
|
91
|
+
|
92
|
+
# create getters and setters for subclasses of JSONObject
|
93
|
+
# based on their JSON_ATTRIBUTES Hash.
|
94
|
+
#
|
95
|
+
# This method can't be private, cuz we want to call it from a
|
96
|
+
# Zeitwerk callback when subclasses are loaded.
|
97
|
+
##############################
|
98
|
+
def self.parse_json_attributes
|
99
|
+
# nothing to do if JSON_ATTRIBUTES is not defined for this class
|
100
|
+
return unless defined? self::JSON_ATTRIBUTES
|
101
|
+
|
102
|
+
self::JSON_ATTRIBUTES.each do |attr_name, attr_def|
|
103
|
+
if attribute_already_parsed?(attr_name)
|
104
|
+
Windoo.load_msg "Ancestor of #{self} has already parsed attribute #{attr_name}"
|
105
|
+
next
|
106
|
+
end
|
107
|
+
|
108
|
+
Windoo.load_msg "Defining getters and setters for attribute '#{attr_name}' of #{self}"
|
109
|
+
|
110
|
+
# there can be only one (primary ident)
|
111
|
+
if attr_def[:identifier] == :primary
|
112
|
+
raise Windoo::UnsupportedError, 'Two identifiers marked as :primary' if @got_primary
|
113
|
+
|
114
|
+
@got_primary = true
|
115
|
+
end
|
116
|
+
|
117
|
+
# create getter unless the attr is write only
|
118
|
+
define_getters attr_name, attr_def unless attr_def[:writeonly]
|
119
|
+
|
120
|
+
# Don't crete setters for readonly attrs, or immutable objects
|
121
|
+
define_setters attr_name, attr_def if mutable? && !attr_def[:readonly]
|
122
|
+
|
123
|
+
json_attributes_parsed << attr_name
|
124
|
+
end # do |attr_name, attr_def|
|
125
|
+
end # parse_object_model
|
126
|
+
|
127
|
+
# have we already parsed our JSON_ATTRIBUTES? If so,
|
128
|
+
# we shoudn't do it again, and this can be used to check
|
129
|
+
def self.json_attributes_parsed
|
130
|
+
@json_attributes_parsed ||= []
|
131
|
+
end
|
132
|
+
|
133
|
+
# Used by auto-generated setters and .create to validate new values.
|
134
|
+
#
|
135
|
+
# returns a valid value or raises an exception
|
136
|
+
#
|
137
|
+
# This method only validates single values. When called from multi-value
|
138
|
+
# setters, it is used for each value individually.
|
139
|
+
#
|
140
|
+
# @param attr_name[Symbol], a top-level key from OAPI_PROPERTIES for this class
|
141
|
+
#
|
142
|
+
# @param value [Object] the value to validate for that attribute.
|
143
|
+
#
|
144
|
+
# @return [Object] The validated, possibly converted, value.
|
145
|
+
#
|
146
|
+
def self.validate_attr(attr_name, value)
|
147
|
+
attr_def = json_attributes[attr_name]
|
148
|
+
raise ArgumentError, "Unknown attribute: #{attr_name} for #{self} objects" unless attr_def
|
149
|
+
|
150
|
+
# validate the value based on the OAPI definition.
|
151
|
+
Windoo::Validate.json_attr value, attr_def: attr_def, attr_name: attr_name
|
152
|
+
end # validate_attr(attr_name, value)
|
153
|
+
|
154
|
+
# Private Class Methods
|
155
|
+
#####################################
|
156
|
+
|
157
|
+
# has one of our superclasses already parsed this attribute?
|
158
|
+
##############################
|
159
|
+
def self.attribute_already_parsed?(attr_name)
|
160
|
+
superclass.respond_to?(:json_attributes_parsed) && superclass.json_attributes_parsed.include?(attr_name)
|
161
|
+
end
|
162
|
+
|
163
|
+
# create a getter for an attribute, and any aliases needed
|
164
|
+
##############################
|
165
|
+
def self.define_getters(attr_name, attr_def)
|
166
|
+
Windoo.load_msg "..Defining getter method #{self}##{attr_name}"
|
167
|
+
|
168
|
+
define_method(attr_name) { instance_variable_get("@#{attr_name}") }
|
169
|
+
|
170
|
+
# all booleans get predicate ? aliases
|
171
|
+
alias_method("#{attr_name}?", attr_name) if attr_def[:class] == :Boolean
|
172
|
+
end # create getters
|
173
|
+
private_class_method :define_getters
|
174
|
+
|
175
|
+
# create setter for an attribute
|
176
|
+
##############################
|
177
|
+
def self.define_setters(attr_name, attr_def)
|
178
|
+
# readonly values don't get setters
|
179
|
+
return if attr_def[:readonly]
|
180
|
+
|
181
|
+
Windoo.load_msg "..Defining setter method #{self}##{attr_name}="
|
182
|
+
|
183
|
+
define_method("#{attr_name}=") do |new_value|
|
184
|
+
new_value = validate_attr attr_name, new_value
|
185
|
+
old_value = instance_variable_get("@#{attr_name}")
|
186
|
+
return if new_value == old_value
|
187
|
+
|
188
|
+
# always update the server before the local
|
189
|
+
# value, so server errors will be raised first
|
190
|
+
# But only if this is a server object
|
191
|
+
# and
|
192
|
+
update_on_server(attr_name, new_value) if ok_to_send_to_server?(attr_name)
|
193
|
+
|
194
|
+
instance_variable_set("@#{attr_name}", new_value)
|
195
|
+
end # define method
|
196
|
+
end # define_setters
|
197
|
+
private_class_method :define_setters
|
198
|
+
|
199
|
+
##############################
|
200
|
+
# def self.create_array_setters(attr_name, attr_def)
|
201
|
+
# create_full_array_setters(attr_name, attr_def)
|
202
|
+
# create_append_setters(attr_name, attr_def)
|
203
|
+
# create_prepend_setters(attr_name, attr_def)
|
204
|
+
# create_insert_setters(attr_name, attr_def)
|
205
|
+
# create_delete_setters(attr_name, attr_def)
|
206
|
+
# create_delete_at_setters(attr_name, attr_def)
|
207
|
+
# create_delete_if_setters(attr_name, attr_def)
|
208
|
+
# end # def create_multi_setters
|
209
|
+
# private_class_method :create_array_setters
|
210
|
+
|
211
|
+
# The attr=(newval) setter method for array values
|
212
|
+
# ##############################
|
213
|
+
# def self.create_full_array_setters(attr_name, attr_def)
|
214
|
+
# Windoo.load_msg "Creating multi-value setter method #{self}##{attr_name}="
|
215
|
+
|
216
|
+
# define_method("#{attr_name}=") do |new_value|
|
217
|
+
# initialize_multi_value_attr_array attr_name
|
218
|
+
|
219
|
+
# raise Windoo::InvalidDataError, "Value for '#{attr_name}=' must be an Array" unless new_value.is_a? Array
|
220
|
+
|
221
|
+
# # validate each item of the new array
|
222
|
+
# new_value.map! { |item| validate_attr attr_name, item }
|
223
|
+
|
224
|
+
# # now validate the array as a whole for oapi constraints
|
225
|
+
# Windoo::Validate.array_constraints(new_value, attr_def: attr_def, attr_name: attr_name)
|
226
|
+
|
227
|
+
# old_value = instance_variable_get("@#{attr_name}")
|
228
|
+
# return if new_value == old_value
|
229
|
+
|
230
|
+
# instance_variable_set("@#{attr_name}", new_value)
|
231
|
+
# end # define method
|
232
|
+
|
233
|
+
# return unless attr_def[:aliases]
|
234
|
+
# end # create_full_array_setter
|
235
|
+
# private_class_method :create_full_array_setters
|
236
|
+
|
237
|
+
# The attr_append(newval) setter method for array values
|
238
|
+
##############################
|
239
|
+
# def self.create_append_setters(attr_name, attr_def)
|
240
|
+
# Windoo.load_msg "Creating multi-value setter method #{self}##{attr_name}_append"
|
241
|
+
|
242
|
+
# define_method("#{attr_name}_append") do |new_value|
|
243
|
+
# initialize_multi_value_attr_array attr_name
|
244
|
+
|
245
|
+
# new_value = validate_attr attr_name, new_value
|
246
|
+
|
247
|
+
# new_array = instance_variable_get("@#{attr_name}")
|
248
|
+
# new_array << new_value
|
249
|
+
|
250
|
+
# # now validate the array as a whole for oapi constraints
|
251
|
+
# Windoo::Validate.array_constraints(new_array, attr_def: attr_def, attr_name: attr_name)
|
252
|
+
# end # define method
|
253
|
+
|
254
|
+
# # always have a << alias
|
255
|
+
# alias_method "#{attr_name}<<", "#{attr_name}_append"
|
256
|
+
# end # create_append_setters
|
257
|
+
# private_class_method :create_append_setters
|
258
|
+
|
259
|
+
# The attr_prepend(newval) setter method for array values
|
260
|
+
##############################
|
261
|
+
# def self.create_prepend_setters(attr_name, attr_def)
|
262
|
+
# Windoo.load_msg "Creating multi-value setter method #{self}##{attr_name}_prepend"
|
263
|
+
|
264
|
+
# define_method("#{attr_name}_prepend") do |new_value|
|
265
|
+
# initialize_multi_value_attr_array attr_name
|
266
|
+
|
267
|
+
# new_value = validate_attr attr_name, new_value
|
268
|
+
|
269
|
+
# new_array = instance_variable_get("@#{attr_name}")
|
270
|
+
# new_array.unshift new_value
|
271
|
+
|
272
|
+
# # now validate the array as a whole for oapi constraints
|
273
|
+
# Windoo::Validate.array_constraints(new_array, attr_def: attr_def, attr_name: attr_name)
|
274
|
+
# end # define method
|
275
|
+
# end # create_prepend_setters
|
276
|
+
# private_class_method :create_prepend_setters
|
277
|
+
|
278
|
+
# The attr_insert(index, newval) setter method for array values
|
279
|
+
# def self.create_insert_setters(attr_name, attr_def)
|
280
|
+
# Windoo.load_msg "Creating multi-value setter method #{self}##{attr_name}_insert"
|
281
|
+
|
282
|
+
# define_method("#{attr_name}_insert") do |index, new_value|
|
283
|
+
# initialize_multi_value_attr_array attr_name
|
284
|
+
|
285
|
+
# new_value = validate_attr attr_name, new_value
|
286
|
+
|
287
|
+
# new_array = instance_variable_get("@#{attr_name}")
|
288
|
+
# new_array.insert index, new_value
|
289
|
+
|
290
|
+
# # now validate the array as a whole for oapi constraints
|
291
|
+
# Windoo::Validate.array_constraints(new_array, attr_def: attr_def, attr_name: attr_name)
|
292
|
+
# end # define method
|
293
|
+
# end # create_insert_setters
|
294
|
+
# private_class_method :create_insert_setters
|
295
|
+
|
296
|
+
# The attr_delete(val) setter method for array values
|
297
|
+
##############################
|
298
|
+
# def self.create_delete_setters(attr_name, attr_def)
|
299
|
+
# Windoo.load_msg "Creating multi-value setter method #{self}##{attr_name}_delete"
|
300
|
+
|
301
|
+
# define_method("#{attr_name}_delete") do |val|
|
302
|
+
# initialize_multi_value_attr_array attr_name
|
303
|
+
|
304
|
+
# new_array = instance_variable_get("@#{attr_name}")
|
305
|
+
# new_array.delete val
|
306
|
+
# return if old_array == new_array
|
307
|
+
|
308
|
+
# # now validate the array as a whole for oapi constraints
|
309
|
+
# Windoo::Validate.array_constraints(new_array, attr_def: attr_def, attr_name: attr_name)
|
310
|
+
# end # define method
|
311
|
+
# end # create_insert_setters
|
312
|
+
# private_class_method :create_delete_setters
|
313
|
+
|
314
|
+
# The attr_delete_at(index) setter method for array values
|
315
|
+
##############################
|
316
|
+
# def self.create_delete_at_setters(attr_name, attr_def)
|
317
|
+
# Windoo.load_msg "Creating multi-value setter method #{self}##{attr_name}_delete_at"
|
318
|
+
|
319
|
+
# define_method("#{attr_name}_delete_at") do |index|
|
320
|
+
# initialize_multi_value_attr_array attr_name
|
321
|
+
|
322
|
+
# new_array = instance_variable_get("@#{attr_name}")
|
323
|
+
# deleted = new_array.delete_at index
|
324
|
+
# return unless deleted
|
325
|
+
|
326
|
+
# # now validate the array as a whole for oapi constraints
|
327
|
+
# Windoo::Validate.array_constraints(new_array, attr_def: attr_def, attr_name: attr_name)
|
328
|
+
# end # define method
|
329
|
+
# end # create_insert_setters
|
330
|
+
# private_class_method :create_delete_at_setters
|
331
|
+
|
332
|
+
# The attr_delete_if(block) setter method for array values
|
333
|
+
##############################
|
334
|
+
# def self.create_delete_if_setters(attr_name, attr_def)
|
335
|
+
# Windoo.load_msg "Creating multi-value setter method #{self}##{attr_name}_delete_if"
|
336
|
+
|
337
|
+
# define_method("#{attr_name}_delete_if") do |&block|
|
338
|
+
# initialize_multi_value_attr_array attr_name
|
339
|
+
|
340
|
+
# new_array = instance_variable_get("@#{attr_name}")
|
341
|
+
# old_array = new_array.dup
|
342
|
+
# new_array.delete_if(&block)
|
343
|
+
# return if old_array == new_array
|
344
|
+
|
345
|
+
# # now validate the array as a whole for oapi constraints
|
346
|
+
# Windoo::Validate.array_constraints(new_array, attr_def: attr_def, attr_name: attr_name)
|
347
|
+
# end # define method
|
348
|
+
# end # create_insert_setters
|
349
|
+
# private_class_method :create_delete_if_setters
|
350
|
+
|
351
|
+
# Constructor
|
352
|
+
######################
|
353
|
+
def initialize(**init_data)
|
354
|
+
@init_data = init_data
|
355
|
+
@init_data.each do |key, val|
|
356
|
+
next unless self.class.json_attributes.key? key
|
357
|
+
|
358
|
+
# The inst var is always a dup of the init_data, so that
|
359
|
+
# changes to it don't affect the init data.
|
360
|
+
ruby_val =
|
361
|
+
if val && self.class.json_attributes[key][:to_ruby]
|
362
|
+
Windoo::Converters.send self.class.json_attributes[key][:to_ruby], val.dup
|
363
|
+
else
|
364
|
+
val.dup
|
365
|
+
end
|
366
|
+
|
367
|
+
instance_variable_set "@#{key}", ruby_val
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
# Public Instance Methods
|
372
|
+
#####################
|
373
|
+
|
374
|
+
# @return [Hash] The data to be sent to the API, as a Hash
|
375
|
+
# to be converted to JSON before sending to the JPAPI
|
376
|
+
#
|
377
|
+
# This is currently only used when creating new objects in the API.
|
378
|
+
# Updates happen immediately per attribute, from the setter methods,
|
379
|
+
# sending only the new value to the server.
|
380
|
+
#
|
381
|
+
# It might also be used in the future to export JSON title
|
382
|
+
# definitions to import into other Title Servers.
|
383
|
+
#
|
384
|
+
def to_api
|
385
|
+
api_data = {}
|
386
|
+
attrs_for_save = self.class.json_attributes.keys
|
387
|
+
|
388
|
+
attrs_for_save.each do |attr_name|
|
389
|
+
attr_def = self.class.json_attributes[attr_name]
|
390
|
+
next if attr_def[:do_not_send]
|
391
|
+
|
392
|
+
raw_value = instance_variable_get "@#{attr_name}"
|
393
|
+
|
394
|
+
api_data[attr_name] =
|
395
|
+
if raw_value.nil?
|
396
|
+
nil
|
397
|
+
else
|
398
|
+
single_to_api(raw_value, attr_def)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
api_data
|
402
|
+
end
|
403
|
+
|
404
|
+
# @return [String] the JSON to be sent to the API for this
|
405
|
+
# object
|
406
|
+
#
|
407
|
+
# This is only used when creating new objects in the API.
|
408
|
+
# Updates happen immediately from the setter methods,
|
409
|
+
# sending only the new value to the server.
|
410
|
+
#
|
411
|
+
def to_json(*_args)
|
412
|
+
JSON.pretty_generate to_api
|
413
|
+
end
|
414
|
+
|
415
|
+
# Only selected items are displayed with prettyprint
|
416
|
+
# otherwise its too much data in irb.
|
417
|
+
#
|
418
|
+
# @return [Array] the desired instance_variables
|
419
|
+
#
|
420
|
+
def pretty_print_instance_variables
|
421
|
+
instance_variables - PP_OMITTED_INST_VARS
|
422
|
+
end
|
423
|
+
|
424
|
+
# Private Instance Methods
|
425
|
+
#####################################
|
426
|
+
private
|
427
|
+
|
428
|
+
# should an attribute be sent to the server when running the setter?
|
429
|
+
# Only if its an APICollection, and the attribute is not 'do_not_send'
|
430
|
+
def ok_to_send_to_server?(attr_name)
|
431
|
+
self.class.ancestors.include?(Windoo::Mixins::APICollection) && \
|
432
|
+
!self.class.json_attributes.dig(attr_name, :do_not_send)
|
433
|
+
end
|
434
|
+
|
435
|
+
# Initialize a multi-values attribute as an empty array
|
436
|
+
# if it hasn't been created yet
|
437
|
+
def initialize_multi_value_attr_array(attr_name)
|
438
|
+
return if instance_variable_get("@#{attr_name}").is_a? Array
|
439
|
+
|
440
|
+
instance_variable_set("@#{attr_name}", [])
|
441
|
+
end
|
442
|
+
|
443
|
+
# wrapper for class method
|
444
|
+
def validate_attr(attr_name, value)
|
445
|
+
self.class.validate_attr attr_name, value
|
446
|
+
end
|
447
|
+
|
448
|
+
# call to_api on a single value if it knows that method
|
449
|
+
# or pass it to the converter module if needed
|
450
|
+
# otherwise, the value is good as is
|
451
|
+
def single_to_api(raw_value, attr_def)
|
452
|
+
if attr_def[:to_api]
|
453
|
+
Windoo::Converters.send attr_def[:to_api], raw_value.dup
|
454
|
+
elsif raw_value.respond_to?(:to_api)
|
455
|
+
raw_value.to_api
|
456
|
+
else
|
457
|
+
raw_value
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
# Call to_api on an array value
|
462
|
+
#
|
463
|
+
def multi_to_api(raw_array, attr_def)
|
464
|
+
raw_array ||= []
|
465
|
+
raw_array.map { |raw_value| single_to_api(raw_value, attr_def) }.compact
|
466
|
+
end
|
467
|
+
|
468
|
+
end # class JSONObject
|
469
|
+
|
470
|
+
end # module BaseClasses
|
471
|
+
|
472
|
+
end # module Windoo
|