u3d 0.9.3 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +54 -0
- data/.github_changelog_generator +4 -0
- data/.rubocop.yml +14 -0
- data/CHANGELOG.md +80 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +42 -5
- data/README.md +68 -6
- data/Rakefile +25 -1
- data/docs/assets/u3d_list.png +0 -0
- data/docs/assets/u3d_run_current.png +0 -0
- data/docs/assets/u3d_sanitize.png +0 -0
- data/examples/Example1/Gemfile +2 -0
- data/examples/Example2/Gemfile +2 -0
- data/lib/u3d/commands.rb +87 -104
- data/lib/u3d/commands_generator.rb +23 -23
- data/lib/u3d/download_validator.rb +74 -0
- data/lib/u3d/downloader.rb +113 -265
- data/lib/u3d/iniparser.rb +24 -5
- data/lib/u3d/installation.rb +167 -0
- data/lib/u3d/installer.rb +62 -196
- data/lib/u3d/log_analyzer.rb +2 -0
- data/lib/u3d/unity_project.rb +45 -0
- data/lib/u3d/unity_runner.rb +30 -21
- data/lib/u3d/unity_version_definition.rb +60 -0
- data/lib/u3d/unity_versions.rb +54 -32
- data/lib/u3d/utils.rb +10 -0
- data/lib/u3d/version.rb +1 -1
- data/lib/u3d_core/command_executor.rb +23 -12
- data/lib/u3d_core/command_runner.rb +7 -1
- data/lib/u3d_core/credentials.rb +2 -2
- data/lib/u3d_core/globals.rb +4 -2
- data/lib/u3d_core/helper.rb +8 -6
- data/lib/u3d_core/ui/implementations/shell.rb +1 -1
- data/u3d.gemspec +3 -1
- metadata +28 -5
data/lib/u3d/log_analyzer.rb
CHANGED
@@ -24,6 +24,7 @@ require 'json'
|
|
24
24
|
|
25
25
|
module U3d
|
26
26
|
# Analyzes log by filtering output along a set of rules
|
27
|
+
# rubocop:disable ClassLength, PerceivedComplexity, BlockNesting
|
27
28
|
class LogAnalyzer
|
28
29
|
RULES_PATH = File.expand_path('../../../config/log_rules.json', __FILE__)
|
29
30
|
MEMORY_SIZE = 10
|
@@ -227,4 +228,5 @@ module U3d
|
|
227
228
|
true
|
228
229
|
end
|
229
230
|
end
|
231
|
+
# rubocop:enable ClassLength, PerceivedComplexity, BlockNesting
|
230
232
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
## --- BEGIN LICENSE BLOCK ---
|
2
|
+
# Copyright (c) 2016-present WeWantToKnow AS
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
# SOFTWARE.
|
21
|
+
## --- END LICENSE BLOCK ---
|
22
|
+
|
23
|
+
require 'u3d_core/helper'
|
24
|
+
|
25
|
+
module U3d
|
26
|
+
class UnityProject
|
27
|
+
attr_reader :path
|
28
|
+
|
29
|
+
def initialize(path)
|
30
|
+
@path = path
|
31
|
+
end
|
32
|
+
|
33
|
+
def exist?
|
34
|
+
Dir.exist?("#{@path}/Assets") && Dir.exist?("#{@path}/ProjectSettings")
|
35
|
+
end
|
36
|
+
|
37
|
+
def editor_version
|
38
|
+
require 'yaml'
|
39
|
+
yaml = YAML.safe_load(File.read("#{@path}/ProjectSettings/ProjectVersion.txt"))
|
40
|
+
version = yaml['m_EditorVersion']
|
41
|
+
version.gsub!(/(\d+\.\d+\.\d+)(?:x)?(\w\d+)(?:Linux)?/, '\1\2') if Helper.linux?
|
42
|
+
version
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/u3d/unity_runner.rb
CHANGED
@@ -28,16 +28,7 @@ module U3d
|
|
28
28
|
# Launches Unity with given arguments
|
29
29
|
class Runner
|
30
30
|
def run(installation, args, raw_logs: false)
|
31
|
-
log_file =
|
32
|
-
|
33
|
-
if log_file # we wouldn't want to do that for the default log file.
|
34
|
-
File.delete(log_file) if File.file?(log_file) # We only delete real files
|
35
|
-
else
|
36
|
-
log_file = installation.default_log_file
|
37
|
-
end
|
38
|
-
|
39
|
-
Utils.ensure_dir File.dirname(log_file)
|
40
|
-
FileUtils.touch(log_file) unless File.exist? log_file
|
31
|
+
log_file = find_and_prepare_logfile(installation, args)
|
41
32
|
|
42
33
|
tail_thread = Thread.new do
|
43
34
|
begin
|
@@ -64,7 +55,7 @@ module U3d
|
|
64
55
|
else
|
65
56
|
args.map!(&:shellescape)
|
66
57
|
end
|
67
|
-
|
58
|
+
|
68
59
|
U3dCore::CommandExecutor.execute(command: args, print_all: true)
|
69
60
|
ensure
|
70
61
|
sleep 1
|
@@ -72,20 +63,38 @@ module U3d
|
|
72
63
|
end
|
73
64
|
end
|
74
65
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
66
|
+
def find_and_prepare_logfile(installation, args)
|
67
|
+
log_file = Runner.find_logFile_in_args(args)
|
68
|
+
|
69
|
+
if log_file # we wouldn't want to do that for the default log file.
|
70
|
+
File.delete(log_file) if File.file?(log_file) # We only delete real files
|
71
|
+
else
|
72
|
+
log_file = installation.default_log_file
|
73
|
+
end
|
78
74
|
|
79
|
-
|
80
|
-
|
75
|
+
Utils.ensure_dir File.dirname(log_file)
|
76
|
+
FileUtils.touch(log_file) unless File.exist? log_file
|
77
|
+
log_file
|
81
78
|
end
|
82
79
|
|
83
|
-
|
84
|
-
|
85
|
-
args
|
86
|
-
|
80
|
+
class << self
|
81
|
+
# rubocop:disable MethodName
|
82
|
+
def find_logFile_in_args(args)
|
83
|
+
# rubocop:enable MethodName
|
84
|
+
find_arg_in_args('-logFile', args)
|
85
|
+
end
|
86
|
+
|
87
|
+
def find_projectpath_in_args(args)
|
88
|
+
find_arg_in_args('-projectpath', args)
|
89
|
+
end
|
90
|
+
|
91
|
+
def find_arg_in_args(arg_to_find, args)
|
92
|
+
raise 'Only arguments of type array supported right now' unless args.is_a?(Array)
|
93
|
+
args.each_with_index do |arg, index|
|
94
|
+
return args[index + 1] if arg == arg_to_find && index < args.count - 1
|
95
|
+
end
|
96
|
+
nil
|
87
97
|
end
|
88
|
-
nil
|
89
98
|
end
|
90
99
|
|
91
100
|
private
|
@@ -0,0 +1,60 @@
|
|
1
|
+
## --- BEGIN LICENSE BLOCK ---
|
2
|
+
# Copyright (c) 2016-present WeWantToKnow AS
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
# SOFTWARE.
|
21
|
+
## --- END LICENSE BLOCK ---
|
22
|
+
|
23
|
+
require 'u3d/iniparser'
|
24
|
+
|
25
|
+
module U3d
|
26
|
+
class UnityVersionDefinition
|
27
|
+
attr_accessor :version, :os, :url, :ini
|
28
|
+
|
29
|
+
def initialize(version, os, cached_versions)
|
30
|
+
@version = version
|
31
|
+
@os = os
|
32
|
+
# Cache is assumed to be correct
|
33
|
+
@url = cached_versions ? cached_versions[version] : nil
|
34
|
+
begin
|
35
|
+
@ini = INIparser.load_ini(version, cached_versions, os: os)
|
36
|
+
rescue => e
|
37
|
+
UI.error "Could not load INI file for version #{@version} on #{@os}: #{e}"
|
38
|
+
@ini = nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def available_packages
|
43
|
+
@ini.keys
|
44
|
+
end
|
45
|
+
|
46
|
+
def [](key)
|
47
|
+
return nil unless @ini
|
48
|
+
@ini[key]
|
49
|
+
end
|
50
|
+
|
51
|
+
def size_in_kb(package)
|
52
|
+
return -1 unless @ini[package] && @ini[package]['size']
|
53
|
+
@os == :win ? @ini[package]['size'] * 1024 : @ini[package]['size']
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.create_fake(version, size, url)
|
57
|
+
INIparser.create_linux_ini(version, size, url)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/u3d/unity_versions.rb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
# SOFTWARE.
|
21
21
|
## --- END LICENSE BLOCK ---
|
22
22
|
|
23
|
-
require 'u3d/
|
23
|
+
require 'u3d/unity_version_definition'
|
24
24
|
require 'u3d_core/helper'
|
25
25
|
require 'net/http'
|
26
26
|
|
@@ -91,7 +91,52 @@ module U3d
|
|
91
91
|
class << self
|
92
92
|
def list_available
|
93
93
|
UI.message 'Loading Unity releases'
|
94
|
-
|
94
|
+
|
95
|
+
data = linux_forum_page_content
|
96
|
+
|
97
|
+
versions = {}
|
98
|
+
results = data.scan(LINUX_DOWNLOAD_DATED)
|
99
|
+
results.each do |capt|
|
100
|
+
save_package_size(capt[1], capt[0])
|
101
|
+
versions[capt[1]] = capt[0]
|
102
|
+
end
|
103
|
+
|
104
|
+
response = nil
|
105
|
+
results = data.scan(LINUX_DOWNLOAD_RECENT_PAGE)
|
106
|
+
results.each do |page|
|
107
|
+
response = linux_forum_version_page_content(page[0])
|
108
|
+
if response.is_a? Net::HTTPSuccess
|
109
|
+
capt = response.body.match(LINUX_DOWNLOAD_RECENT_FILE)
|
110
|
+
if capt && capt[1] && capt[2]
|
111
|
+
ver = capt[2].delete('x')
|
112
|
+
UI.important "Version #{ver} does not match standard Unity versions" unless ver =~ Utils::UNITY_VERSION_REGEX
|
113
|
+
save_package_size(ver, capt[1])
|
114
|
+
versions[ver] = capt[1]
|
115
|
+
else
|
116
|
+
UI.error("Could not retrieve a fitting file from #{url}")
|
117
|
+
end
|
118
|
+
else
|
119
|
+
UI.error("Could not access #{url}")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
if versions.count.zero?
|
123
|
+
UI.important 'Found no releases'
|
124
|
+
else
|
125
|
+
UI.success "Found #{versions.count} releases."
|
126
|
+
end
|
127
|
+
versions
|
128
|
+
end
|
129
|
+
|
130
|
+
def save_package_size(version, url)
|
131
|
+
size = Utils.get_url_content_length(url)
|
132
|
+
if size
|
133
|
+
UnityVersionDefinition.create_fake(version, size, url)
|
134
|
+
else
|
135
|
+
UI.important "u3d tried to get the size of the installer for version #{version}, but wasn't able to"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def linux_forum_page_content
|
95
140
|
response = nil
|
96
141
|
data = ''
|
97
142
|
uri = URI(UNITY_LINUX_DOWNLOADS)
|
@@ -148,38 +193,15 @@ module U3d
|
|
148
193
|
else raise "Request failed with status #{response.code}"
|
149
194
|
end
|
150
195
|
end
|
151
|
-
data
|
152
|
-
|
153
|
-
results = data.scan(LINUX_DOWNLOAD_DATED)
|
154
|
-
results.each do |capt|
|
155
|
-
versions[capt[1]] = capt[0]
|
156
|
-
end
|
196
|
+
data
|
197
|
+
end
|
157
198
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
request = Net::HTTP::Get.new uri
|
164
|
-
response = http.request request
|
165
|
-
end
|
166
|
-
if response.kind_of? Net::HTTPSuccess
|
167
|
-
capt = response.body.match(LINUX_DOWNLOAD_RECENT_FILE)
|
168
|
-
if capt && capt[1] && capt[2]
|
169
|
-
versions[capt[2].delete('x')] = capt[1]
|
170
|
-
else
|
171
|
-
UI.error("Could not retrieve a fitting file from #{url}")
|
172
|
-
end
|
173
|
-
else
|
174
|
-
UI.error("Could not access #{url}")
|
175
|
-
end
|
176
|
-
end
|
177
|
-
if versions.count.zero?
|
178
|
-
UI.important 'Found no releases'
|
179
|
-
else
|
180
|
-
UI.success "Found #{versions.count} releases."
|
199
|
+
def linux_forum_version_page_content(url)
|
200
|
+
uri = URI(url)
|
201
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
202
|
+
request = Net::HTTP::Get.new uri
|
203
|
+
return http.request request
|
181
204
|
end
|
182
|
-
versions
|
183
205
|
end
|
184
206
|
end
|
185
207
|
end
|
data/lib/u3d/utils.rb
CHANGED
@@ -58,6 +58,16 @@ module U3d
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
def get_url_content_length(url)
|
62
|
+
uri = URI(url)
|
63
|
+
size = nil
|
64
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
65
|
+
response = http.request_head url
|
66
|
+
size = Integer(response['Content-Length'])
|
67
|
+
end
|
68
|
+
size
|
69
|
+
end
|
70
|
+
|
61
71
|
def hashfile(file_path, blocksize: 65_536)
|
62
72
|
require 'digest'
|
63
73
|
raise ArgumentError, 'Not a file' unless File.file?(file_path)
|
data/lib/u3d/version.rb
CHANGED
@@ -21,7 +21,7 @@
|
|
21
21
|
## --- END LICENSE BLOCK ---
|
22
22
|
|
23
23
|
module U3d
|
24
|
-
VERSION = '0.9.
|
24
|
+
VERSION = '0.9.4'.freeze
|
25
25
|
DESCRIPTION = 'Provides numerous tools for installing, managing and running the Unity3D game engine from command line.'.freeze
|
26
26
|
UNITY_VERSIONS_NOTE = "Unity3d uses the following version formatting: 0.0.0x0. The \'x\' can takes different values:\n"\
|
27
27
|
"\t. 'f' are the main release candidates for Unity3d\n"\
|
@@ -61,23 +61,19 @@ module U3dCore
|
|
61
61
|
print_all = true if U3dCore::Globals.verbose?
|
62
62
|
prefix ||= {}
|
63
63
|
|
64
|
-
output = []
|
65
64
|
command = command.join(' ') if command.is_a?(Array)
|
66
65
|
UI.command(command) if print_command
|
67
66
|
|
68
67
|
# this is only used to show the "Loading text"...
|
69
68
|
UI.command_output(loading) if print_all && loading
|
70
69
|
|
71
|
-
if admin
|
72
|
-
cred = U3dCore::Credentials.new(user: ENV['USER'])
|
73
|
-
if Helper.windows?
|
74
|
-
raise CredentialsError, "The command \'#{command}\' must be run in administrative shell" unless has_admin_privileges?
|
75
|
-
else
|
76
|
-
command = "sudo -k && echo #{cred.password.shellescape} | sudo -S bash -c \"#{command}\""
|
77
|
-
end
|
78
|
-
UI.verbose 'Admin privileges granted for command execution'
|
79
|
-
end
|
70
|
+
command = grant_admin_privileges(command) if admin
|
80
71
|
|
72
|
+
execute_command(command: command, print_all: print_all, error: error, prefix: prefix)
|
73
|
+
end
|
74
|
+
|
75
|
+
def execute_command(command: nil, print_all: nil, error: nil, prefix: nil)
|
76
|
+
output = []
|
81
77
|
begin
|
82
78
|
status = U3dCore::Runner.run(command) do |stdin, _stdout, _pid|
|
83
79
|
stdin.each do |l|
|
@@ -109,7 +105,9 @@ module U3dCore
|
|
109
105
|
return output.join("\n")
|
110
106
|
end
|
111
107
|
|
108
|
+
# rubocop:disable PredicateName
|
112
109
|
def has_admin_privileges?
|
110
|
+
# rubocop:enable PredicateName
|
113
111
|
if Helper.windows?
|
114
112
|
begin
|
115
113
|
result = system('reg query HKU\\S-1-5-19', out: File::NULL, err: File::NULL)
|
@@ -120,8 +118,8 @@ module U3dCore
|
|
120
118
|
credentials = U3dCore::Credentials.new(user: ENV['USER'])
|
121
119
|
begin
|
122
120
|
result = system("sudo -k && echo #{credentials.password.shellescape} | sudo -S /usr/bin/whoami",
|
123
|
-
|
124
|
-
|
121
|
+
out: File::NULL,
|
122
|
+
err: File::NULL)
|
125
123
|
rescue
|
126
124
|
result = false
|
127
125
|
end
|
@@ -130,6 +128,19 @@ module U3dCore
|
|
130
128
|
# returns false if result is nil (command execution fail)
|
131
129
|
return (result ? true : false)
|
132
130
|
end
|
131
|
+
|
132
|
+
def grant_admin_privileges(command)
|
133
|
+
cred = U3dCore::Credentials.new(user: ENV['USER'])
|
134
|
+
if Helper.windows?
|
135
|
+
raise CredentialsError, "The command \'#{command}\' must be run in administrative shell" unless has_admin_privileges?
|
136
|
+
else
|
137
|
+
command = "sudo -k && echo #{cred.password.shellescape} | sudo -S bash -c \"#{command}\""
|
138
|
+
end
|
139
|
+
UI.verbose 'Admin privileges granted for command execution'
|
140
|
+
command
|
141
|
+
end
|
133
142
|
end
|
143
|
+
|
144
|
+
private_class_method :execute_command
|
134
145
|
end
|
135
146
|
end
|
@@ -21,6 +21,8 @@
|
|
21
21
|
# SOFTWARE.
|
22
22
|
## --- END LICENSE BLOCK ---
|
23
23
|
|
24
|
+
require 'English'
|
25
|
+
|
24
26
|
module U3dCore
|
25
27
|
# this module is meant to be private to this lib
|
26
28
|
module Runner
|
@@ -60,17 +62,21 @@ module U3dCore
|
|
60
62
|
yield r, w, p
|
61
63
|
# if the process has closed, ruby might raise an exception if we try
|
62
64
|
# to do I/O on a closed stream. This behavior is platform specific
|
65
|
+
# rubocop:disable HandleExceptions
|
63
66
|
rescue Errno::EIO
|
67
|
+
# rubocop:enable HandleExceptions
|
64
68
|
ensure
|
65
69
|
begin
|
66
70
|
Process.wait p
|
67
71
|
# The process might have exited.
|
68
72
|
# This behavior is also ruby version dependent.
|
73
|
+
# rubocop:disable HandleExceptions
|
69
74
|
rescue Errno::ECHILD, PTY::ChildExited
|
70
75
|
end
|
76
|
+
# rubocop:enable HandleExceptions
|
71
77
|
end
|
72
78
|
end
|
73
|
-
|
79
|
+
$CHILD_STATUS.exitstatus
|
74
80
|
end
|
75
81
|
end
|
76
82
|
|
data/lib/u3d_core/credentials.rb
CHANGED
@@ -105,8 +105,8 @@ module U3dCore
|
|
105
105
|
UI.message 'Deleting credentials from the keychain'
|
106
106
|
Security::InternetPassword.delete(server: MAC_U3D_SERVER)
|
107
107
|
end
|
108
|
-
|
109
|
-
UI.verbose 'Keychain may store invalid credentials for u3d'
|
108
|
+
elsif Helper.mac?
|
109
|
+
UI.verbose 'Keychain may store invalid credentials for u3d'
|
110
110
|
end
|
111
111
|
end
|
112
112
|
end
|
data/lib/u3d_core/globals.rb
CHANGED
@@ -33,7 +33,7 @@ module U3dCore
|
|
33
33
|
attr_writer :verbose, :log_timestamps, :use_keychain, :do_not_login
|
34
34
|
|
35
35
|
def attributes
|
36
|
-
@attributes ||= ((methods - public_instance_methods).grep(/=$/) - [
|
36
|
+
@attributes ||= ((methods - public_instance_methods).grep(/=$/) - %i[<= >=]).map do |s|
|
37
37
|
a = s.to_s
|
38
38
|
a[0..(a.length - 2)] # remove the '='
|
39
39
|
end
|
@@ -69,7 +69,8 @@ module U3dCore
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
def
|
72
|
+
def respond_to_missing?(method_sym, include_private = false)
|
73
|
+
# rubocop:disable GuardClause
|
73
74
|
if method_sym.to_s =~ /^with_(.*)$/
|
74
75
|
return attributes.include? Regexp.last_match(1)
|
75
76
|
elsif method_sym.to_s =~ /^(.*)\?$/
|
@@ -77,6 +78,7 @@ module U3dCore
|
|
77
78
|
else
|
78
79
|
super
|
79
80
|
end
|
81
|
+
# rubocop:enable GuardClause
|
80
82
|
end
|
81
83
|
end
|
82
84
|
private_class_method :is?, :with, :attributes
|