inspec-core 4.18.51 → 4.18.85
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +61 -0
- data/README.md +3 -3
- data/inspec-core.gemspec +51 -0
- data/lib/bundles/inspec-supermarket/cli.rb +1 -0
- data/lib/inspec/backend.rb +49 -47
- data/lib/inspec/base_cli.rb +2 -2
- data/lib/inspec/cached_fetcher.rb +4 -0
- data/lib/inspec/cli.rb +5 -0
- data/lib/inspec/config.rb +1 -1
- data/lib/inspec/control_eval_context.rb +131 -199
- data/lib/inspec/dependencies/requirement.rb +1 -1
- data/lib/inspec/dependencies/resolver.rb +46 -0
- data/lib/inspec/dsl_shared.rb +25 -3
- data/lib/inspec/fetcher.rb +0 -3
- data/lib/inspec/fetcher/git.rb +4 -0
- data/lib/inspec/fetcher/url.rb +1 -2
- data/lib/inspec/file_provider.rb +4 -2
- data/lib/inspec/library_eval_context.rb +37 -37
- data/lib/inspec/plugin/v1/plugin_types/fetcher.rb +27 -0
- data/lib/inspec/plugin/v1/plugins.rb +0 -1
- data/lib/inspec/profile.rb +8 -6
- data/lib/inspec/profile_context.rb +74 -9
- data/lib/inspec/profile_vendor.rb +48 -3
- data/lib/inspec/resource.rb +192 -41
- data/lib/inspec/resources/aide_conf.rb +1 -1
- data/lib/inspec/resources/apache_conf.rb +15 -31
- data/lib/inspec/resources/command.rb +1 -1
- data/lib/inspec/resources/crontab.rb +56 -56
- data/lib/inspec/resources/etc_fstab.rb +1 -1
- data/lib/inspec/resources/etc_group.rb +1 -1
- data/lib/inspec/resources/etc_hosts.rb +2 -3
- data/lib/inspec/resources/etc_hosts_allow_deny.rb +1 -1
- data/lib/inspec/resources/file.rb +2 -2
- data/lib/inspec/resources/filesystem.rb +4 -4
- data/lib/inspec/resources/groups.rb +16 -2
- data/lib/inspec/resources/iis_app.rb +1 -1
- data/lib/inspec/resources/ini.rb +1 -2
- data/lib/inspec/resources/mount.rb +2 -2
- data/lib/inspec/resources/oracledb_session.rb +1 -1
- data/lib/inspec/resources/package.rb +22 -0
- data/lib/inspec/resources/passwd.rb +1 -1
- data/lib/inspec/resources/platform.rb +36 -36
- data/lib/inspec/resources/port.rb +1 -1
- data/lib/inspec/resources/postfix_conf.rb +1 -1
- data/lib/inspec/resources/service.rb +23 -15
- data/lib/inspec/resources/users.rb +3 -3
- data/lib/inspec/resources/virtualization.rb +15 -11
- data/lib/inspec/resources/x509_certificate.rb +18 -4
- data/lib/inspec/resources/xinetd_conf.rb +1 -1
- data/lib/inspec/resources/xml.rb +1 -2
- data/lib/inspec/rspec_extensions.rb +12 -0
- data/lib/inspec/rule.rb +63 -22
- data/lib/inspec/utils/filter.rb +2 -0
- data/lib/inspec/utils/parser.rb +244 -240
- data/lib/inspec/utils/simpleconfig.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/matchers/matchers.rb +11 -10
- data/lib/plugins/inspec-compliance/lib/inspec-compliance.rb +3 -0
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb +2 -2
- data/lib/plugins/inspec-init/templates/profiles/aws/README.md +192 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/attributes.yml +2 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/controls/example.rb +39 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +22 -0
- data/lib/plugins/inspec-init/templates/profiles/azure/README.md +56 -0
- data/lib/plugins/inspec-init/templates/profiles/azure/controls/example.rb +14 -0
- data/lib/plugins/inspec-init/templates/profiles/azure/inspec.yml +14 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/README.md +66 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/attributes.yml +2 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/controls/example.rb +27 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/inspec.yml +19 -0
- data/lib/source_readers/inspec.rb +1 -1
- metadata +87 -74
- data/lib/inspec/plugin/v1/plugin_types/resource.rb +0 -176
- data/lib/plugins/inspec-init/templates/profiles/os/libraries/.gitkeep +0 -0
@@ -46,7 +46,7 @@ module Inspec
|
|
46
46
|
req
|
47
47
|
end
|
48
48
|
|
49
|
-
attr_reader :cwd, :opts, :version_constraints
|
49
|
+
attr_reader :cwd, :opts, :version_constraints, :cache
|
50
50
|
def initialize(name, version_constraints, config, opts)
|
51
51
|
@name = name
|
52
52
|
@version_constraints = Array(version_constraints)
|
@@ -57,6 +57,16 @@ module Inspec
|
|
57
57
|
|
58
58
|
detect_duplicates(deps, top_level, path_string)
|
59
59
|
deps.each do |dep|
|
60
|
+
# Calling dep.resolved_source forces a fetch. Handle any airgap chicanery early.
|
61
|
+
if Inspec::Config.cached[:airgap]
|
62
|
+
begin
|
63
|
+
dep.resolved_source
|
64
|
+
rescue Inspec::FetcherFailure
|
65
|
+
Inspec::Log.debug("Failed to fetch #{dep.name}, falling back to archives if possible")
|
66
|
+
retry if fallback_to_archive_on_fetch_failure(dep)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
60
70
|
new_seen_items = seen_items.dup
|
61
71
|
new_path_string = if path_string.empty?
|
62
72
|
dep.name
|
@@ -82,5 +92,41 @@ module Inspec
|
|
82
92
|
Inspec::Log.debug("Dependency traversal complete.") if top_level
|
83
93
|
graph
|
84
94
|
end
|
95
|
+
|
96
|
+
def fallback_to_archive_on_fetch_failure(dep)
|
97
|
+
# This facility is intended to handle situations in which
|
98
|
+
# the failing dependency *is* available in an archive that we have
|
99
|
+
# available as a local dependency. We just need to find the archive and
|
100
|
+
# alter the fetcher to refer to information in the archive.
|
101
|
+
# Note that the vendor cache already should have the archive inflated
|
102
|
+
# for this to work (see warm_cache_from_archives() from profile_vendor.rb)
|
103
|
+
# Refs 4727
|
104
|
+
|
105
|
+
# This is where any existing archives should have been inflated -
|
106
|
+
# that is, this is the vendor cache. Each archive would have a lockfile.
|
107
|
+
cache_path = dep.cache.path
|
108
|
+
worth_retrying = false
|
109
|
+
|
110
|
+
Dir["#{cache_path}/*/inspec.lock"].each do |lockfile_path|
|
111
|
+
lockfile = Inspec::Lockfile.from_file(lockfile_path)
|
112
|
+
dep_set = Inspec::DependencySet.from_lockfile(lockfile, dep.opts)
|
113
|
+
dep2 = dep_set.dep_list[dep.name]
|
114
|
+
next unless dep2
|
115
|
+
|
116
|
+
if dep.opts.key?(:compliance)
|
117
|
+
# This is ugly. The compliance fetcher works differently than the others,
|
118
|
+
# and fails at the resolve stage, not the fetch stage. That means we can't
|
119
|
+
# tweak the fetcher, we have to tweak the deps opts themselves.
|
120
|
+
dep.opts[:sha256] = dep2.opts[:sha256]
|
121
|
+
worth_retrying = true
|
122
|
+
else
|
123
|
+
# All other fetchers can be generalized, because they will survive their constructor.
|
124
|
+
fetcher = dep.fetcher.fetcher # Not the CachedFetcher, but its fetcher
|
125
|
+
made_a_change = fetcher.update_from_opts(dep2.opts)
|
126
|
+
end
|
127
|
+
worth_retrying ||= made_a_change
|
128
|
+
end
|
129
|
+
worth_retrying
|
130
|
+
end
|
85
131
|
end
|
86
132
|
end
|
data/lib/inspec/dsl_shared.rb
CHANGED
@@ -8,6 +8,26 @@ module Inspec
|
|
8
8
|
# It is used whenever the `require 'lib'` is not in libraries.
|
9
9
|
alias __ruby_require require
|
10
10
|
|
11
|
+
##
|
12
|
+
# This is our own require override, to be used in
|
13
|
+
# LibraryEvalContext and ControlEvalContext.
|
14
|
+
#
|
15
|
+
# Any top level libraries file (autoloaded) that requires a
|
16
|
+
# second-level libraries file.
|
17
|
+
#
|
18
|
+
# in load_libraries
|
19
|
+
# in top level libraries file to be autoloaded
|
20
|
+
# that has a require to a known file that is NOT loaded yet
|
21
|
+
#
|
22
|
+
# ProfileContext#initialize
|
23
|
+
# -> library_eval_context
|
24
|
+
#
|
25
|
+
# ProfileContext#load_libraries autoload
|
26
|
+
# -> load_library_file(@library_eval_context)
|
27
|
+
#
|
28
|
+
# probably most of this comment is useless, but it was hard to
|
29
|
+
# discover so I'm adding it for others.
|
30
|
+
|
11
31
|
def require(path)
|
12
32
|
rbpath = path + ".rb"
|
13
33
|
return __ruby_require(path) unless @require_loader.exists?(rbpath)
|
@@ -23,9 +43,11 @@ module Inspec
|
|
23
43
|
# context that provides the correct plane to evaluate all required files to.
|
24
44
|
# It will ensure that embedded calls to `require` still call this
|
25
45
|
# method and get loaded from their correct paths.
|
26
|
-
|
27
|
-
|
28
|
-
|
46
|
+
if defined?(__inspec_binding)
|
47
|
+
__inspec_binding.eval(content, path, line)
|
48
|
+
else
|
49
|
+
eval(content, TOPLEVEL_BINDING, path, line) # rubocop:disable Security/Eval
|
50
|
+
end
|
29
51
|
end
|
30
52
|
end
|
31
53
|
end
|
data/lib/inspec/fetcher.rb
CHANGED
data/lib/inspec/fetcher/git.rb
CHANGED
data/lib/inspec/fetcher/url.rb
CHANGED
@@ -127,8 +127,7 @@ module Inspec::Fetcher
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def sha256
|
130
|
-
|
131
|
-
OpenSSL::Digest::SHA256.digest(File.read(file)).unpack("H*")[0]
|
130
|
+
@archive_shasum ||= OpenSSL::Digest::SHA256.digest(File.read(@archive_path || temp_archive_path)).unpack("H*")[0]
|
132
131
|
end
|
133
132
|
|
134
133
|
def file_type_from_remote(remote)
|
data/lib/inspec/file_provider.rb
CHANGED
@@ -66,7 +66,7 @@ module Inspec
|
|
66
66
|
end
|
67
67
|
|
68
68
|
class DirProvider < FileProvider
|
69
|
-
attr_reader :files
|
69
|
+
attr_reader :files, :path
|
70
70
|
def initialize(path)
|
71
71
|
@files = if File.file?(path)
|
72
72
|
[path]
|
@@ -209,8 +209,10 @@ module Inspec
|
|
209
209
|
def walk_tar(path, &callback)
|
210
210
|
tar_file = Zlib::GzipReader.open(path)
|
211
211
|
Gem::Package::TarReader.new(tar_file, &callback)
|
212
|
+
rescue => e
|
213
|
+
raise Inspec::Error, "Error opening/processing #{path}: #{e.message}"
|
212
214
|
ensure
|
213
|
-
tar_file.close
|
215
|
+
tar_file.close if tar_file
|
214
216
|
end
|
215
217
|
end # class TarProvider
|
216
218
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "inspec/
|
1
|
+
require "inspec/resource"
|
2
2
|
require "inspec/dsl_shared"
|
3
3
|
|
4
4
|
module Inspec
|
@@ -12,44 +12,44 @@ module Inspec
|
|
12
12
|
# registry used by all dsl methods bound to the resource registry
|
13
13
|
# passed into the #create constructor.
|
14
14
|
#
|
15
|
-
#
|
16
15
|
class LibraryEvalContext
|
16
|
+
# rubocop:disable Naming/ConstantName
|
17
|
+
Inspec = :nope! # see #initialize below
|
18
|
+
# rubocop:enable Naming/ConstantName
|
19
|
+
|
20
|
+
##
|
21
|
+
# Include a custom `require` method that gets used when this
|
22
|
+
# context is used to eval source. See lib/inspec/dsl_shared.rb for
|
23
|
+
# more details.
|
24
|
+
include ::Inspec::DSL::RequireOverride
|
25
|
+
|
17
26
|
def self.create(registry, require_loader)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
c3.const_set(:Inspec, c2)
|
46
|
-
res = c3.new(require_loader)
|
47
|
-
|
48
|
-
# Provide the local binding for this context which is necessary for
|
49
|
-
# calls to `require` to create all dependent objects in the correct
|
50
|
-
# context.
|
51
|
-
res.instance_variable_set("@inspec_binding", res.instance_eval("binding"))
|
52
|
-
res
|
27
|
+
Class.new(LibraryEvalContext).new(registry, require_loader)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Provide the local binding for this context which is
|
31
|
+
# necessary for calls to `require` to create all dependent
|
32
|
+
# objects in the correct context.
|
33
|
+
attr_accessor :__inspec_binding
|
34
|
+
|
35
|
+
def initialize(registry, require_loader)
|
36
|
+
@require_loader = require_loader
|
37
|
+
# rubocop:disable Style/RedundantSelf
|
38
|
+
self.__inspec_binding = self.instance_eval { binding }
|
39
|
+
# rubocop:enable Style/RedundantSelf
|
40
|
+
|
41
|
+
@res_klass = Class.new ::Inspec::Resource
|
42
|
+
@res_klass.__resource_registry = registry
|
43
|
+
|
44
|
+
# NOTE: this *must* be a subclass of LibraryEvalContext to work
|
45
|
+
self.class.const_set :Inspec, self # BYPASS! See resource below
|
46
|
+
end
|
47
|
+
|
48
|
+
# Fake for Inspec.resource in lib/inspec/resource.rb that provides
|
49
|
+
# our own Resource subclass that has its own private __resource_registry
|
50
|
+
def resource(version)
|
51
|
+
::Inspec.validate_resource_dsl_version!(version)
|
52
|
+
@res_klass
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
@@ -65,6 +65,33 @@ module Inspec
|
|
65
65
|
raise "Fetcher #{self} does not implement `cache_key()`. This is required for terminal fetchers."
|
66
66
|
end
|
67
67
|
|
68
|
+
#
|
69
|
+
# This optional method may be used after a failed fetch. If the fetcher
|
70
|
+
# can be updated with information that might lead to a successful
|
71
|
+
# retrieval of alternative content, this method may be called.
|
72
|
+
#
|
73
|
+
# Default implementation makes a peculiar assumption that the class has
|
74
|
+
# a ivar named @archive_shasum and you have a fetcher opt that pairs with
|
75
|
+
# it named sha256, and those are the only two that matter for updating.
|
76
|
+
#
|
77
|
+
# Return TrueClass if the fetcher was updated and a retry is in order
|
78
|
+
# Return FalseClass if the update contained no useful information
|
79
|
+
# and a retry should not be attempted
|
80
|
+
def update_from_opts(opts)
|
81
|
+
changed = @archive_shasum != opts[:sha256]
|
82
|
+
@archive_shasum = opts[:sha256]
|
83
|
+
changed
|
84
|
+
end
|
85
|
+
|
86
|
+
# Helper for above; usful when the subclass ivars whose
|
87
|
+
# names exactly match the names of the fetcher options.
|
88
|
+
def update_ivar_from_opt(opt_name, opts)
|
89
|
+
ivar_sym = "@#{opt_name}".to_sym
|
90
|
+
changed = instance_variable_get(ivar_sym) != opts[opt_name]
|
91
|
+
instance_variable_set(ivar_sym, opts[opt_name])
|
92
|
+
changed
|
93
|
+
end
|
94
|
+
|
68
95
|
#
|
69
96
|
# relative_target is provided to keep compatibility with 3rd
|
70
97
|
# party plugins.
|
@@ -5,7 +5,6 @@ module Inspec
|
|
5
5
|
# NOTE: the autoloading here is rendered moot by the fact that
|
6
6
|
# all core plugins are `require`'d by the base inspec.rb
|
7
7
|
module Plugins
|
8
|
-
autoload :Resource, "inspec/plugin/v1/plugin_types/resource"
|
9
8
|
autoload :CLI, "inspec/plugin/v1/plugin_types/cli"
|
10
9
|
autoload :Fetcher, "inspec/plugin/v1/plugin_types/fetcher"
|
11
10
|
autoload :SourceReader, "inspec/plugin/v1/plugin_types/source_reader"
|
data/lib/inspec/profile.rb
CHANGED
@@ -250,6 +250,7 @@ module Inspec
|
|
250
250
|
# this metadata if the parent profile is supported.
|
251
251
|
if supports_platform? && !d.supports_platform?
|
252
252
|
# since ruby 1.9 hashes are ordered so we can just use index values here
|
253
|
+
# TODO: NO! this is a violation of encapsulation to an extreme
|
253
254
|
metadata.dependencies[i][:status] = "skipped"
|
254
255
|
msg = "Skipping profile: '#{d.name}' on unsupported platform: '#{d.backend.platform.name}/#{d.backend.platform.release}'."
|
255
256
|
metadata.dependencies[i][:skip_message] = msg
|
@@ -259,13 +260,14 @@ module Inspec
|
|
259
260
|
# load them again when we dive down. This needs to be re-done.
|
260
261
|
metadata.dependencies[i][:status] = "loaded"
|
261
262
|
end
|
262
|
-
|
263
|
+
|
264
|
+
# rubocop:disable Layout/ExtraSpacing
|
265
|
+
c = d.load_libraries # !!!RECURSE!!!
|
263
266
|
@runner_context.add_resources(c)
|
264
267
|
end
|
265
268
|
|
266
|
-
|
267
|
-
|
268
|
-
end
|
269
|
+
# TODO: why?!? we own both sides of this code
|
270
|
+
libs = libraries.map(&:reverse)
|
269
271
|
|
270
272
|
@runner_context.load_libraries(libs)
|
271
273
|
@libraries_loaded = true
|
@@ -312,11 +314,11 @@ module Inspec
|
|
312
314
|
end
|
313
315
|
|
314
316
|
# add information about the required inputs
|
315
|
-
if
|
317
|
+
if params[:inputs].nil? || params[:inputs].empty?
|
316
318
|
# convert to array for backwards compatability
|
317
319
|
res[:inputs] = []
|
318
320
|
else
|
319
|
-
res[:inputs] =
|
321
|
+
res[:inputs] = params[:inputs].values.map(&:to_hash)
|
320
322
|
end
|
321
323
|
res[:sha256] = sha256
|
322
324
|
res[:parent_profile] = parent_profile unless parent_profile.nil?
|
@@ -13,6 +13,7 @@ module Inspec
|
|
13
13
|
new(profile.name, backend, { "profile" => profile, "check_mode" => profile.check_mode })
|
14
14
|
end
|
15
15
|
|
16
|
+
attr_reader :library_eval_context
|
16
17
|
attr_reader :backend, :profile_name, :profile_id, :resource_registry
|
17
18
|
attr_accessor :rules
|
18
19
|
def initialize(profile_id, backend, conf)
|
@@ -52,14 +53,18 @@ module Inspec
|
|
52
53
|
end
|
53
54
|
|
54
55
|
def to_resources_dsl
|
55
|
-
|
56
|
+
DomainSpecificLunacy.create_dsl(self)
|
56
57
|
end
|
57
58
|
|
58
59
|
def control_eval_context
|
59
|
-
@control_eval_context ||=
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
@control_eval_context ||=
|
61
|
+
Inspec::ControlEvalContext.new(self,
|
62
|
+
to_resources_dsl,
|
63
|
+
@backend,
|
64
|
+
@conf,
|
65
|
+
dependencies,
|
66
|
+
@require_loader,
|
67
|
+
@skip_only_if_eval)
|
63
68
|
end
|
64
69
|
|
65
70
|
def reload_dsl
|
@@ -121,10 +126,14 @@ module Inspec
|
|
121
126
|
|
122
127
|
libs.sort_by! { |l| l[1] } # Sort on source path so load order is deterministic
|
123
128
|
libs.each do |content, source, line|
|
129
|
+
next unless source.end_with?(".rb")
|
130
|
+
|
124
131
|
path = source
|
125
132
|
if source.start_with?(lib_prefix)
|
126
133
|
path = source.sub(lib_prefix, "")
|
127
|
-
|
134
|
+
no_subdir = File.dirname(path) == "."
|
135
|
+
|
136
|
+
autoloads.push(path) if no_subdir
|
128
137
|
end
|
129
138
|
|
130
139
|
@require_loader.add(path, content, source, line)
|
@@ -132,10 +141,10 @@ module Inspec
|
|
132
141
|
|
133
142
|
# load all files directly that are flat inside the libraries folder
|
134
143
|
autoloads.each do |path|
|
135
|
-
|
136
|
-
|
137
|
-
load_library_file(*@require_loader.load(path)) unless @require_loader.loaded?(path)
|
144
|
+
load_library_file(*@require_loader.load(path)) unless
|
145
|
+
@require_loader.loaded?(path)
|
138
146
|
end
|
147
|
+
|
139
148
|
reload_dsl
|
140
149
|
end
|
141
150
|
|
@@ -199,5 +208,61 @@ module Inspec
|
|
199
208
|
|
200
209
|
pid.to_s + "/" + rid.to_s
|
201
210
|
end
|
211
|
+
|
212
|
+
module DomainSpecificLunacy
|
213
|
+
def self.create_dsl(profile_context)
|
214
|
+
Module.new do
|
215
|
+
include DomainSpecificLunacy
|
216
|
+
add_methods(profile_context)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.included(mod)
|
221
|
+
mod.extend ClassMethods
|
222
|
+
end
|
223
|
+
|
224
|
+
def resource_class(profile_name, resource_name)
|
225
|
+
inner_context = if profile_name == profile_context.profile_id
|
226
|
+
profile_context
|
227
|
+
else
|
228
|
+
profile_context.subcontext_by_name(profile_name)
|
229
|
+
end
|
230
|
+
|
231
|
+
raise ProfileNotFound, "Cannot find profile named: #{profile_name}" if inner_context.nil?
|
232
|
+
|
233
|
+
inner_context.resource_registry[resource_name]
|
234
|
+
end
|
235
|
+
|
236
|
+
module ClassMethods
|
237
|
+
def add_methods(profile_context)
|
238
|
+
backend = profile_context.backend
|
239
|
+
|
240
|
+
define_method(:profile_context) { profile_context }
|
241
|
+
define_method(:inspec) { backend }
|
242
|
+
|
243
|
+
add_registry_methods(profile_context)
|
244
|
+
end
|
245
|
+
|
246
|
+
def add_registry_methods(profile_context)
|
247
|
+
be = profile_context.backend
|
248
|
+
bec = be.class
|
249
|
+
|
250
|
+
registry = profile_context.resource_registry
|
251
|
+
registry.each do |id, r|
|
252
|
+
define_method(id) { |*args| r.new(be, id.to_s, *args) }
|
253
|
+
|
254
|
+
next if be.respond_to?(id)
|
255
|
+
|
256
|
+
bec.define_method(id) { |*args| r.new(be, id.to_s, *args) }
|
257
|
+
end
|
258
|
+
end # add_resource_methods
|
259
|
+
end # ClassMethods
|
260
|
+
end # DomainSpecificLunacy
|
261
|
+
end # ProfileContext
|
262
|
+
end
|
263
|
+
|
264
|
+
if RUBY_VERSION < "2.5"
|
265
|
+
class Module
|
266
|
+
public :define_method
|
202
267
|
end
|
203
268
|
end
|