shellopts 2.0.0.pre.1 → 2.0.0.pre.8

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.
@@ -3,9 +3,9 @@ require 'shellopts/idr.rb'
3
3
 
4
4
  module ShellOpts
5
5
  module Idr
6
- # Generates an Idr::Program from an Ast::Program object
7
- def self.generate(ast, messenger)
8
- Idr::Program.new(ast, messenger)
6
+ # Generates an Idr::Program from a ShellOpts object
7
+ def self.generate(shellopts)
8
+ Idr::Program.new(shellopts)
9
9
  end
10
10
  end
11
11
  end
@@ -18,7 +18,7 @@ module ShellOpts
18
18
  attr_reader :option_list
19
19
 
20
20
  # List of commands in declaration order
21
- attr_reader :command_list
21
+ attr_reader :subcommand_list
22
22
 
23
23
  # Multihash from option key or names (both short and long names) to option. This
24
24
  # means an option can occur more than once as the hash value
@@ -31,9 +31,9 @@ module ShellOpts
31
31
  # Sub-commands of this command. Is a multihash from sub-command key or
32
32
  # name to command object. Lazily constructed because subcommands are added
33
33
  # after initialization
34
- def commands()
35
- @command_multihash ||= @command_list.flat_map { |command|
36
- command.identifiers.map { |name| [name, command] }
34
+ def subcommands()
35
+ @subcommand_multihash ||= @subcommand_list.flat_map { |subcommand|
36
+ subcommand.identifiers.map { |name| [name, subcommand] }
37
37
  }.to_h
38
38
  end
39
39
 
@@ -41,16 +41,15 @@ module ShellOpts
41
41
  # if this is the root object. name is the name of the command (without
42
42
  # the exclamation mark), and option_list a list of Option objects
43
43
  def initialize(parent, name, option_list)
44
- super("#{name}!".to_sym)
45
- @name = name
44
+ super("#{name}!".to_sym, name)
46
45
  parent.attach(self) if parent
47
46
  @option_list = option_list
48
- @command_list = []
47
+ @subcommand_list = []
49
48
  end
50
49
 
51
50
  # Return key for the identifier
52
51
  def identifier2key(ident)
53
- options[ident]&.key || commands[ident]&.key
52
+ options[ident]&.key || subcommands[ident]&.key
54
53
  end
55
54
 
56
55
  # Return list of identifiers for the command
@@ -65,16 +64,16 @@ module ShellOpts
65
64
  yield if block_given?
66
65
  puts "options:"
67
66
  indent { option_list.each { |opt| opt.dump } }
68
- puts "commands: "
69
- indent { command_list.each { |cmd| cmd.dump } }
67
+ puts "subcommands: "
68
+ indent { subcommand_list.each { |cmd| cmd.dump } }
70
69
  }
71
70
  end
72
71
  # :nocov:
73
72
 
74
73
  protected
75
- def attach(command)
76
- command.instance_variable_set(:@parent, self)
77
- @command_list << command
74
+ def attach(subcommand)
75
+ subcommand.instance_variable_set(:@parent, self)
76
+ @subcommand_list << subcommand
78
77
  end
79
78
  end
80
79
  end
@@ -10,14 +10,22 @@ module ShellOpts
10
10
  # Key (Symbol) of node. Unique within the enclosing command
11
11
  attr_reader :key
12
12
 
13
- def initialize(key)
14
- @key = key
13
+ # Name of node. The name of an option is without the prefixed '-' or
14
+ # '--', the name of a command is without the suffixed '!'. Note that name
15
+ # collisions can happen between options and commands names
16
+ attr_reader :name
17
+
18
+ def initialize(key, name)
19
+ @key, @name = key, name
15
20
  end
16
21
 
17
22
  # :nocov:
18
23
  def dump(&block)
19
24
  puts key.inspect
20
- indent { yield } if block_given?
25
+ indent {
26
+ puts "name: #{name.inspect}"
27
+ yield if block_given?
28
+ }
21
29
  end
22
30
  # :nocov:
23
31
  end
@@ -27,7 +27,8 @@ module ShellOpts
27
27
  # informal name of the option argument (eg. 'FILE') or nil if not present
28
28
  def initialize(short_names, long_names, flags, label = nil)
29
29
  @key_name = long_names.first || short_names.first
30
- super(@key_name.sub(/^-+/, "").to_sym)
30
+ name = @key_name.sub(/^-+/, "")
31
+ super(name.to_sym, name)
31
32
  @short_names, @long_names = short_names, long_names
32
33
  @flags = flags.map { |flag| [flag, true] }.to_h
33
34
  @label = label
@@ -17,7 +17,7 @@ module ShellOpts
17
17
  def usage
18
18
  (
19
19
  render_options(option_list) +
20
- command_list.map { |cmd| render_command(cmd) } +
20
+ subcommand_list.map { |cmd| render_subcommand(cmd) } +
21
21
  args
22
22
  ).flatten.join(" ")
23
23
  end
@@ -32,9 +32,9 @@ module ShellOpts
32
32
  # :nocov:
33
33
 
34
34
  private
35
- def render_command(command)
36
- [command.name] + render_options(command.option_list) +
37
- command.command_list.map { |cmd| render_command(cmd) }.flatten
35
+ def render_subcommand(subcommand)
36
+ [subcommand.name] + render_options(subcommand.option_list) +
37
+ subcommand.subcommand_list.map { |cmd| render_subcommand(cmd) }.flatten
38
38
  end
39
39
 
40
40
  def render_options(options)
@@ -13,15 +13,14 @@ module ShellOpts
13
13
  # and a value. Options have their (optional) argument as value while
14
14
  # commands use +self+ as value
15
15
  class Node
16
+ # Parent node. nil for the top-level Program object
17
+ attr_reader :parent
18
+
16
19
  # Unique key (within context) for the option or command. nil for the
17
20
  # top-level Program object
18
- #
19
- # It is usually the first long option if present and else the first short
20
- # option turned into a Symbol by first removing prefixed dashed, eg.
21
- # '--all' becomes :all
22
21
  attr_reader :key
23
22
 
24
- # Name of command and option as used on the command line
23
+ # Name of command or option as used on the command line
25
24
  attr_reader :name
26
25
 
27
26
  # Value of node. This can be a simple value (String, Integer, or Float),
@@ -33,10 +32,13 @@ module ShellOpts
33
32
  # arguments or if an optional argument is missing.
34
33
  attr_reader :value
35
34
 
35
+ # The top-level Program object
36
+ def program() @program ||= (parent&.program || self) end
37
+
36
38
  protected
37
39
  # Copy arguments into instance variables
38
- def initialize(ast, key, name, value)
39
- @ast, @key, @name, @value = ast, key, name, value
40
+ def initialize(parent, ast, key, name, value)
41
+ @parent, @ast, @key, @name, @value = parent, ast, key, name, value
40
42
  end
41
43
 
42
44
  # The AST node for this Idr object
@@ -54,9 +56,9 @@ module ShellOpts
54
56
  protected
55
57
  # Initialize with defauls from the Ast. +value+ is set to true if option
56
58
  # doesn't take an argument
57
- def initialize(ast)
59
+ def initialize(parent, ast)
58
60
  value = ast.grammar.argument? ? ast.value : true
59
- super(ast, ast.key, ast.name, value)
61
+ super(parent, ast, ast.key, ast.name, value)
60
62
  end
61
63
  end
62
64
 
@@ -71,9 +73,9 @@ module ShellOpts
71
73
  alias :values :value
72
74
 
73
75
  # Name is set to the key name and value to an array of option values
74
- def initialize(key, name, options)
76
+ def initialize(parent, key, name, options)
75
77
  @names = options.map(&:name)
76
- super(nil, key, name, options.map(&:value))
78
+ super(parent, nil, key, name, options.map(&:value))
77
79
  end
78
80
  end
79
81
 
@@ -91,13 +93,13 @@ module ShellOpts
91
93
  attr_reader :subcommand
92
94
 
93
95
  # True if ident is declared
94
- def declared?(ident) option?(ident) || command?(ident) end
96
+ def declared?(ident) option?(ident) || subcommand?(ident) end
95
97
 
96
98
  # True if ident is declared as an option
97
99
  def option?(ident) grammar.options.key?(ident) end
98
100
 
99
101
  # True if ident is declared as a command
100
- def command?(ident) grammar.commands.key?(ident) end
102
+ def subcommand?(ident) grammar.subcommands.key?(ident) end
101
103
 
102
104
  # True if ident is present
103
105
  def key?(ident)
@@ -120,8 +122,8 @@ module ShellOpts
120
122
  end
121
123
 
122
124
  # Apply defaults recursively. Values can be lambdas that will be evaluated to
123
- # get the default value
124
- def apply(defaults = {}) end
125
+ # get the default value. TODO
126
+ def apply(defaults = {}) raise InternalError, "Not implemented" end
125
127
 
126
128
  # Return options and command as an array
127
129
  def to_a() @ast.values end
@@ -129,49 +131,52 @@ module ShellOpts
129
131
  # Return options and command as a hash. The hash also define the
130
132
  # singleton method #subcommand that returns the key of the subcommand
131
133
  #
132
- # +key+ controls the type of keys used: +:key+ (the default) use the
133
- # symbolic key, +:name+ use key_name. Note that using +:name+ can cause name collisions between
134
- # option and command names and that #to_s raises an exception if it detects a collision
134
+ # +key_type+ controls the type of keys used: +:key+ (the default) use the
135
+ # symbolic key, +:name+ use #name. Note that using +:name+ can cause
136
+ # name collisions between option and command names
135
137
  #
136
138
  # +aliases+ maps from key to replacement key (which could be any object).
137
139
  # +aliases+ can be used to avoid name collisions between options and
138
- # commands
140
+ # commands when using key_format: :name
139
141
  #
140
- # IDEA: Make subcommand _not_ follow the +key+ setting so that setting key to
141
- # IDEA: Add a singleton method #subcommand to the hash
142
+ # IDEA: Add a singleton methods to the hash with #name, #usage, etc.
142
143
  #
143
- def to_h(use: :key, aliases: {})
144
+ def to_h(key_type: ::ShellOpts.default_key_type, aliases: {})
145
+ keys = map_keys(key_type, aliases)
144
146
  value = {}
145
147
  value.define_singleton_method(:subcommand) { nil }
146
- options.values.each { |opt|
147
- ident = aliases[opt.key] || (use == :key ? opt.key : opt.ast.grammar.key_name)
148
- !value.key?(ident) or raise ConversionError, "Duplicate key: #{ident.inspect}"
148
+ options.values.each { |opt| # includes subcommand
149
+ key = keys[opt.key]
149
150
  case opt
150
151
  when Option
151
- value[ident] = opt.value
152
+ value[key] = opt.value
152
153
  when Command
153
- value[ident] = opt.value.to_h
154
- value.define_singleton_method(:subcommand) { ident } # Redefine
154
+ value[key] = opt.value.to_h(key_type: key_type, aliases: aliases[opt.key] || {})
155
+ value.define_singleton_method(:subcommand) { key } # Redefine
155
156
  else
157
+ # :nocov:
156
158
  raise InternalError, "Oops"
159
+ # :nocov:
157
160
  end
158
161
  }
159
162
  value
160
163
  end
161
164
 
162
165
  # Return options and command as a struct
163
- def to_struct(key = :key, aliases = {}) OptionStruct.new(self, key, aliases) end
166
+ def to_struct(key_type: ::ShellOpts.default_key_type, aliases: {})
167
+ OptionStruct.new(self, key_type, aliases)
168
+ end
164
169
 
165
170
  protected
166
171
  # Initialize an Idr::Command object and all dependent objects
167
- def initialize(ast)
168
- super(ast, ast.key, ast.name, self)
169
- @option_list = ast.options.map { |node| SimpleOption.new(node) }
170
- @subcommand = Command.new(ast.command) if ast.command
172
+ def initialize(parent, ast)
173
+ super(parent, ast, ast.key, ast.name, self)
174
+ @option_list = ast.options.map { |node| SimpleOption.new(self, node) }
175
+ @subcommand = Command.new(self, ast.subcommand) if ast.subcommand
171
176
  @options = @option_list.group_by { |option| option.key }.map { |key, option_list|
172
177
  option =
173
178
  if ast.grammar.options[key].repeated?
174
- OptionGroup.new(key, ast.grammar.options[key].key_name, option_list)
179
+ OptionGroup.new(self, key, ast.grammar.options[key].key_name, option_list)
175
180
  else
176
181
  option_list.first
177
182
  end
@@ -179,30 +184,52 @@ module ShellOpts
179
184
  }.to_h
180
185
  @options[subcommand.key] = @subcommand if @subcommand
181
186
  end
187
+
188
+ # Internal-key to used-key map. Checks for reserved words and
189
+ # name-collisions
190
+ def map_keys(key_type, aliases, reserved_words = [])
191
+ keys = {}
192
+ used_keys = {}
193
+ (grammar.option_list + grammar.subcommand_list).each { |node|
194
+ internal_key = node.key
195
+ key = aliases[internal_key] || (key_type == :name ? node.name.to_sym : internal_key)
196
+ !reserved_words.include?(key) or
197
+ raise ::ShellOpts::ConversionError, "'#{key}' is a reserved word"
198
+ !used_keys.key?(key) or
199
+ raise ::ShellOpts::ConversionError, "Name collision between '--#{key}' and '#{key}!'"
200
+ keys[internal_key] = key
201
+ used_keys[key] = true
202
+ }
203
+ keys
204
+ end
182
205
  end
183
206
 
184
207
  class Program < Command
208
+ # Name of program
209
+ def name() @shellopts.name end
210
+ def name=(name) @shellopts.name = name end
211
+
212
+ # Usage string
213
+ def usage() @shellopts.usage end
214
+ def usage=(usage) @shellopts.usage = usage end
215
+
185
216
  # #key is nil for the top-level Program object
186
217
  def key() nil end
187
218
 
188
219
  # Remaining command line arguments
189
- def args() @ast.arguments end
190
-
191
- # Messenger object that is used to emit error messages. It should
192
- # implement #error(*args) and #fail(*args)
193
- attr_reader :messenger
220
+ def args() @shellopts.args end
194
221
 
195
222
  # Initialize the top-level Idr::Program object
196
- def initialize(ast, messenger)
197
- @messenger = messenger
198
- super(ast)
223
+ def initialize(shellopts)
224
+ @shellopts = shellopts
225
+ super(nil, shellopts.ast)
199
226
  end
200
227
 
201
228
  # Emit error message and a usage description before exiting with status 1
202
- def error(*args) messenger.error(*error_messages) end
229
+ def error(*args) @shellopts.error(*error_messages) end
203
230
 
204
231
  # Emit error message before exiting with status 1
205
- def fail(*args) messenger.fail(*error_messages) end
232
+ def fail(*args) @shellopts.fail(*error_messages) end
206
233
  end
207
234
  end
208
235
  end
@@ -0,0 +1,10 @@
1
+
2
+ module ShellOpts
3
+ # Gives access to the ruby main object
4
+ module Main
5
+ CALLER_RE = /^.*:in `<main>'$/
6
+ def self.main() TOPLEVEL_BINDING.eval("self") end
7
+ end
8
+ end
9
+
10
+
@@ -3,88 +3,8 @@ require 'shellopts/shellopts.rb'
3
3
  require 'shellopts/idr'
4
4
 
5
5
  module ShellOpts
6
- class OptionStruct < BasicObject
7
- # +key=:name+ cause command methods to be named without the exclamation
8
- # mark. It doesn't change how options are named
9
- def self.new(idr, key = :key, aliases = {})
10
- ast = idr.instance_variable_get("@ast")
11
- grammar = ast.grammar
12
- instance = allocate
13
-
14
- # Generate option accessor methods
15
- grammar.option_list.each { |option|
16
- key = alias_key(option.key, aliases)
17
- instance.instance_eval("def #{key}() @#{key} end")
18
- present = set_variable(instance, "@#{key}", idr[option.key])
19
- instance.instance_eval("def #{key}?() #{present} end")
20
- }
21
-
22
- # Generate #subcommand default methods
23
- if !idr.subcommand
24
- instance.instance_eval("def subcommand() nil end")
25
- instance.instance_eval("def subcommand?() false end")
26
- instance.instance_eval("def subcommand!() nil end")
27
- end
28
-
29
- # Generate subcommand methods
30
- grammar.command_list.each { |command|
31
- key = alias_key(command.key, aliases)
32
- if command.key == idr.subcommand&.key
33
- struct = OptionStruct.new(idr.subcommand, aliases[idr.subcommand.key] || {})
34
- set_variable(instance, "@subcommand", struct)
35
- instance.instance_eval("def #{key}() @subcommand end")
36
- instance.instance_eval("def subcommand() :#{key} end")
37
- instance.instance_eval("def subcommand?() true end")
38
- instance.instance_eval("def subcommand!() @subcommand end")
39
- else
40
- instance.instance_eval("def #{key}() nil end")
41
- end
42
- }
43
-
44
- instance
45
- end
46
-
47
- private
48
- # Return class of object. #class is not defined for BasicObjects so this
49
- # method provides an alternative way of getting the class
50
- def self.class_of(object)
51
- # https://stackoverflow.com/a/18621313/2130986
52
- ::Kernel.instance_method(:class).bind(object).call
53
- end
54
-
55
- # Replace key with alias and check against the list of reserved words
56
- def self.alias_key(internal_key, aliases)
57
- key = aliases[internal_key] || internal_key
58
- !RESERVED_WORDS.include?(key.to_s) or
59
- raise ::ShellOpts::ConversionError, "Can't create struct: '#{key}' is a reserved word"
60
- key
61
- end
62
-
63
- # Shorthand helper method. Substitutes the undefined ObjectStruct#instance_variable_set
64
- def self.set_variable(this, var, value)
65
- # https://stackoverflow.com/a/18621313/2130986
66
- ::Kernel.instance_method(:instance_variable_set).bind(this).call(var, value)
67
- end
68
-
69
- BASIC_OBJECT_RESERVED_WORDS = %w(
70
- __id__ __send__ instance_eval instance_exec method_missing
71
- singleton_method_added singleton_method_removed
72
- singleton_method_undefined)
73
- OPTIONS_STRUCT_RESERVED_WORDS = %w(subcommand)
74
- RESERVED_WORDS = BASIC_OBJECT_RESERVED_WORDS + OPTIONS_STRUCT_RESERVED_WORDS
75
- end
76
- end
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
- __END__
86
-
87
- module ShellOpts
6
+ # FIXME: Outdated
7
+ #
88
8
  # Struct representation of options. Usually created by ShellOpts::to_struct
89
9
  #
90
10
  # OptionStruct objects give easy access to configuration option values but
@@ -136,110 +56,93 @@ module ShellOpts
136
56
  # reserved words or with the special #command method
137
57
  #
138
58
  class OptionStruct < BasicObject
139
- # Create a new OptionStruct instance from an AST. The optional
140
- # +options_hash+ argument is used to create subcommands without creating a
141
- # new options_hash argument. It is not meant for end-users. The
142
- # +command_alias+ names the method holding the key for the subcommand (if
143
- # any)
144
- def self.new(ast, options_hash = OptionsHash.new(ast), command_alias: :command)
59
+ # Create a OptionStruct object recursively from an Idr::Command object
60
+ def self.new(idr, key_type, aliases = {})
61
+ # Shorthands
62
+ ast = idr.instance_variable_get("@ast")
63
+ grammar = ast.grammar
64
+
65
+ # Get key map
66
+ keys = idr.send(:map_keys, key_type, aliases, RESERVED_WORDS)
67
+
68
+ # Allocate OptionStruct instance
145
69
  instance = allocate
146
- set_variable(instance, "@__options_hash__", options_hash)
147
70
 
148
- # Check for reserved words and +command_alias+
149
- options_hash.keys.each { |key|
150
- !RESERVED_WORDS.include?(key.to_s) or
151
- raise ::ShellOpts::ConversionError, "Can't create struct: '#{key}' is a reserved word"
152
- key != command_alias or
153
- raise ::ShellOpts::ConversionError, "Can't create struct: '#{key}' is the command alias"
154
- }
71
+ # Set reference to Idr object. Is currently unused
72
+ set_variable(instance, "@__idr__", idr)
155
73
 
156
- # Create accessor methods
157
- ast.grammar.option_list.each { |option|
158
- instance.instance_eval("def #{option.key}() @#{option.key} end")
159
- instance.instance_eval("def #{option.key}?() false end")
74
+ # Generate general option accessor methods
75
+ grammar.option_list.each { |option|
76
+ key = keys[option.key]
77
+ instance.instance_eval("def #{key}() @#{key} end")
78
+ instance.instance_eval("def #{key}?() false end")
160
79
  }
161
- ast.grammar.command_list.each { |command|
162
- instance.instance_eval("def #{command.key}() nil end")
80
+
81
+ # Generate accessor method for present options
82
+ idr.option_list.each { |option|
83
+ key = keys[option.key]
84
+ set_variable(instance, "@#{key}", idr[option.key])
85
+ instance.instance_eval("def #{key}?() true end")
163
86
  }
164
87
 
165
- # Assign values
166
- options_hash.each { |key, value|
167
- if value.is_a?(OptionsHash)
168
- set_variable(instance, "@__command__", OptionStruct.new(value.ast, value))
169
- instance.instance_eval("def #{key}() @__command__ end")
88
+ # Generate general #subcommand methods
89
+ if !idr.subcommand
90
+ instance.instance_eval("def subcommand() nil end")
91
+ instance.instance_eval("def subcommand?() false end")
92
+ instance.instance_eval %(
93
+ def subcommand!(*msgs)
94
+ $stderr.puts "in subcommand!"
95
+ ::Kernel.raise ::ShellOpts::UserError, (msgs.empty? ? 'No command' : msgs.join)
96
+ end
97
+ )
98
+ end
99
+
100
+ # Generate individual subcommand methods
101
+ grammar.subcommand_list.each { |subcommand|
102
+ key = keys[subcommand.key]
103
+ if subcommand.key == idr.subcommand&.key
104
+ struct = OptionStruct.new(idr.subcommand, key_type, aliases[idr.subcommand.key] || {})
105
+ set_variable(instance, "@subcommand", struct)
106
+ instance.instance_eval("def #{key}() @subcommand end")
107
+ instance.instance_eval("def subcommand() :#{key} end")
108
+ instance.instance_eval("def subcommand?() true end")
109
+ instance.instance_eval("def subcommand!(*msgs) :#{key} end")
170
110
  else
171
- set_variable(instance, "@#{key}", value)
172
- instance.instance_eval("def #{key}?() true end")
111
+ instance.instance_eval("def #{key}() nil end")
173
112
  end
174
113
  }
175
114
 
176
- # Command accessor method
177
- instance.instance_eval("def #{command_alias}() @__options_hash__.command end")
178
-
179
115
  instance
180
116
  end
181
117
 
182
- # Return the OptionsHash object from the instance
183
- def self.options_hash(instance)
184
- get_variable(instance, "@__options_hash__")
185
- end
186
-
118
+ private
187
119
  # Return class of object. #class is not defined for BasicObjects so this
188
- # method provides an alternative way of getting the class a BasicObject
120
+ # method provides an alternative way of getting the class
189
121
  def self.class_of(object)
190
122
  # https://stackoverflow.com/a/18621313/2130986
191
123
  ::Kernel.instance_method(:class).bind(object).call
192
124
  end
193
125
 
194
- # Return the number of options and commands
195
- def self.size(instance)
196
- options_hash(instance).size
197
- end
198
-
199
- # Return the option and command keys. The keys are in order of occurrence
200
- # on the command line. A subcommand will always be the last element
201
- def self.keys(instance)
202
- options_hash(instance).keys
203
- end
204
-
205
- # Return the actual option name used on the command line for +name+. Use
206
- # +index+ to select between repeated options. Return the name of the
207
- # program/subcommand if key is nil
208
- def self.name(struct, key = nil, index = nil)
209
- options_hash(struct).name(key, index)
210
- end
211
-
212
- # Return the AST node for the option key or the AST node for the
213
- # OptionStruct if key is nil. Use +index+ to select between repeated
214
- # options. Raise InternalError if key doesn't exists
215
- def self.node(struct, key = nil, index = nil)
216
- options_hash(struct).node(key, index)
217
- end
218
-
219
- # Return key of the command of the struct (possibly nil)
220
- def self.command(struct)
221
- options_hash(struct).command
222
- end
223
-
224
- private
225
- BASIC_OBJECT_RESERVED_WORDS = %w(
226
- __id__ __send__ instance_eval instance_exec method_missing
227
- singleton_method_added singleton_method_removed
228
- singleton_method_undefined)
229
- OPTIONS_STRUCT_RESERVED_WORDS = %w(__options_hash__ __command__)
230
- RESERVED_WORDS = BASIC_OBJECT_RESERVED_WORDS + OPTIONS_STRUCT_RESERVED_WORDS
231
-
232
- # Shorthand helper method. Substitutes the undefined ObjectStruct#instance_variable_set
126
+ # Class method implementation of ObjectStruct#instance_variable_set that is
127
+ # not defined in a BasicObject
233
128
  def self.set_variable(this, var, value)
234
129
  # https://stackoverflow.com/a/18621313/2130986
235
130
  ::Kernel.instance_method(:instance_variable_set).bind(this).call(var, value)
236
131
  end
237
132
 
238
- # Shorthand helper method: Substitutes the undefined ObjectStruct#instance_variable_get
133
+ # Class method implementation of ObjectStruct#instance_variable_get that is
134
+ # not defined in a BasicObject
239
135
  def self.get_variable(this, var)
240
136
  # https://stackoverflow.com/a/18621313/2130986
241
137
  ::Kernel.instance_method(:instance_variable_get).bind(this).call(var)
242
138
  end
139
+
140
+ BASIC_OBJECT_RESERVED_WORDS = %w(
141
+ __id__ __send__ instance_eval instance_exec method_missing
142
+ singleton_method_added singleton_method_removed
143
+ singleton_method_undefined).map(&:to_sym)
144
+ OPTIONS_STRUCT_RESERVED_WORDS = %w(__idr__ subcommand).map(&:to_sym)
145
+ RESERVED_WORDS = BASIC_OBJECT_RESERVED_WORDS + OPTIONS_STRUCT_RESERVED_WORDS
243
146
  end
244
- end
147
+ end
245
148