development 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md ADDED
File without changes
data/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # Development #
2
+
3
+ http://rubygems.org/gems/development
4
+
5
+ # Summary #
6
+
7
+ Manage development contexts, particularly in the context of nested gem dependencies being developed side by side.
8
+
9
+ # Description #
10
+
11
+ Sometimes problems in one gem under development only appear in the context of use in another gem. In these contexts it can be difficult to discern the particular problem case without diving into the code. When gems are nested in multiple levels of dependency, this can become quite frustrating; gem require paths have to be replaced with relative paths, sometimes in multiple places, and it becomes easy to forget that there are relative paths in code, resulting in production code with broken development paths accidentally left in.
12
+
13
+ Development inserts itself in the require process and loads development paths instead of the gem requires used for production code. Which gems load development paths instead of gem requires is determined by a simple configuration file.
14
+
15
+ # Install #
16
+
17
+ * sudo gem install development
18
+
19
+ # Usage #
20
+
21
+ Enabling Development requires two things:
22
+
23
+ ## 1. Require Development ##
24
+
25
+ ```ruby
26
+ begin ; require 'development' ; rescue LoadError ; end
27
+ ```
28
+
29
+ Or a multi-line version if you prefer:
30
+
31
+ ```ruby
32
+ begin
33
+ require 'development'
34
+ rescue LoadError
35
+ end
36
+ ```
37
+
38
+ Doing this rather than simply requiring development ensures that Development can work transparently without requiring even a development dependency.
39
+
40
+ ## 2. Configure Gems Development Should Intercept ##
41
+
42
+ The primary interface to development is the **.development** configuration file, which should be placed in the user's home directory.
43
+
44
+ I would make project-specific .development files a requirement (to avoid accidentally enabling it) but I don't think there is a reliable way to find the project directory based on the require. If you know a way, please let me know!
45
+
46
+ ### Configuration File Example ###
47
+
48
+ ###
49
+ # Ruby 'development' configuration file (.development).
50
+ #
51
+ # * # denotes comment.
52
+ # * Indentation is treated as a line continuation.
53
+ # * Items can be separated by , or simply by whitespace.
54
+ # * Length of whitespace is irrelevant - contiguous whitespace is "one unit".
55
+ #
56
+
57
+ ###
58
+ # Any lines beginning with plain text (not =, +, -, @, !) will be interpreted as general directory expressions.
59
+ # It is not necessary to specify any general directories. Multiple directories may be specified, one per line.
60
+ #
61
+ # Uncomment the line below to look for directories with gem name in ~/ruby_projects. Any directories specified
62
+ # in this way will be used in the case that no explicit specification exists for gem name in question.
63
+ #
64
+ # ~/ruby_projects
65
+
66
+ ###
67
+ # Declare a gemset to group a set of gems and configure them by a single reference.
68
+ #
69
+ # Gems are permitted to be in multiple sets, with first match (from top of .development file downward) winning.
70
+ #
71
+ # =<gemset_name> gem-name, ...
72
+ #
73
+
74
+ =ruby module-cluster
75
+
76
+ =hooked_objects hash-hooked
77
+ array-hooked
78
+ array-sorted
79
+ array-unique
80
+ array-sorted-unique
81
+
82
+ =compositing_objects hash-compositing
83
+ array-compositing
84
+ array-sorted-compositing
85
+ array-unique-compositing
86
+ array-sorted-unique-compositing
87
+
88
+ =ridiculous_power persistence
89
+ magnets
90
+
91
+ ###
92
+ # Declare named locations to associate gems or gemsets with specific locations.
93
+ #
94
+ # +directory_name path, ...
95
+ #
96
+ # Paths that begin with @ will interpolate the directory name as the starting portion of the path.
97
+ #
98
+
99
+ +code ~/Projects
100
+ +ridiculous_power @code/rp
101
+ +ruby @ridiculous_power/ruby
102
+
103
+ +hooked_objects @ruby/hooked_objects
104
+ +compositing_objects @ruby/compositing_objects
105
+
106
+ ###
107
+ # Declare lookup locations for specific gems.
108
+ #
109
+ # Named paths listed on there own
110
+ #
111
+
112
+ @hooked_objects hooked_objects
113
+ @compositing_objects compositing_objects
114
+
115
+ @ridiculous_power ridiculous_power
116
+
117
+ ###
118
+ # !enable and !disable can be used to cause production gems to be used.
119
+ #
120
+ # * !enable or !disable on its own will enable or disable all gems and change the default (enabled/disabled),
121
+ # after which individual gems can be enabled or disabled.
122
+ #
123
+ # * !enable or !disable followed by a gem name or a gemset name will enable or disable that gem/gemset.
124
+ #
125
+ # Nothing is enabled to start. Call !enable to use .development specifications in all cases; after
126
+ # !enable individual gems/sets/paths can be enabled/disabled.
127
+ #
128
+
129
+ !enable
130
+
131
+ # License #
132
+
133
+ (The MIT License)
134
+
135
+ Copyright (c) Ridiculous Power, Asher
136
+
137
+ Permission is hereby granted, free of charge, to any person obtaining
138
+ a copy of this software and associated documentation files (the
139
+ 'Software'), to deal in the Software without restriction, including
140
+ without limitation the rights to use, copy, modify, merge, publish,
141
+ distribute, sublicense, and/or sell copies of the Software, and to
142
+ permit persons to whom the Software is furnished to do so, subject to
143
+ the following conditions:
144
+
145
+ The above copyright notice and this permission notice shall be
146
+ included in all copies or substantial portions of the Software.
147
+
148
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
149
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
150
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
151
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
152
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
153
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
154
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,881 @@
1
+
2
+ require 'array-unique'
3
+
4
+ ###
5
+ # Singleton that manages configurations and requires.
6
+ #
7
+ module ::Development
8
+
9
+ #############
10
+ # loaded? #
11
+ #############
12
+
13
+ ###
14
+ # Query whether gem was loaded via Development rather than standard require.
15
+ #
16
+ # @param gem_name
17
+ #
18
+ # Name of gem.
19
+ #
20
+ # @return [true,false] Whether gem was loaded via Development.
21
+ #
22
+ def loaded?( gem_name )
23
+
24
+ return @loaded_gems.include?( gem_name )
25
+
26
+ end
27
+
28
+ ####################
29
+ # self.directory #
30
+ ####################
31
+
32
+ def self.directory( directory_name )
33
+
34
+ return @named_directories[ directory_name.to_sym ]
35
+
36
+ end
37
+
38
+ #############################
39
+ # self.general_load_paths #
40
+ #############################
41
+
42
+ def self.general_load_paths
43
+
44
+ return @general_load_paths
45
+
46
+ end
47
+
48
+ ############################
49
+ # self.named_directories #
50
+ ############################
51
+
52
+ def self.named_directories
53
+
54
+ return @named_directories
55
+
56
+ end
57
+
58
+ ###########################
59
+ # self.enabled_for_all? #
60
+ ###########################
61
+
62
+ def self.enabled_for_all?
63
+
64
+ return @enable_for_all
65
+
66
+ end
67
+
68
+ #######################
69
+ # self.enabled_gems #
70
+ #######################
71
+
72
+ def self.enabled_gems
73
+
74
+ return @enabled_gems
75
+
76
+ end
77
+
78
+ ########################
79
+ # self.disabled_gems #
80
+ ########################
81
+
82
+ def self.disabled_gems
83
+
84
+ return @disabled_gems
85
+
86
+ end
87
+
88
+ ##################
89
+ # self.gemsets #
90
+ ##################
91
+
92
+ def self.gemsets
93
+
94
+ return @gemsets
95
+
96
+ end
97
+
98
+ ####################
99
+ # self.locations #
100
+ ####################
101
+
102
+ def self.locations
103
+
104
+ return @locations
105
+
106
+ end
107
+
108
+ ###################
109
+ # self.location #
110
+ ###################
111
+
112
+ def self.location( location_name )
113
+
114
+ return @locations[ location_name.to_sym ]
115
+
116
+ end
117
+
118
+ ######################################################################################################################
119
+ private ##########################################################################################################
120
+ ######################################################################################################################
121
+
122
+ ###
123
+ # @private
124
+ #
125
+ # Container to namespace exceptions.
126
+ #
127
+ module Exception
128
+ end
129
+
130
+ ###
131
+ # Name of configuration file: .development.
132
+ #
133
+ ConfigurationFileName = '.development'
134
+
135
+ @enabled_gems = ::Array::Unique.new
136
+ @disabled_gems = ::Array::Unique.new
137
+
138
+ @gemsets = { }
139
+ @gem_locations = { }
140
+
141
+ @general_load_paths = ::Array::Unique.new
142
+
143
+ @loaded_gems = ::Array::Unique.new
144
+
145
+ @named_directories = { }
146
+ @locations = { }
147
+
148
+ @enable_for_all = false
149
+
150
+ ################
151
+ # self.clear #
152
+ ################
153
+
154
+ def self.clear
155
+
156
+ @enabled_gems.clear
157
+ @disabled_gems.clear
158
+ @gemsets.clear
159
+ @general_load_paths.clear
160
+ @loaded_gems.clear
161
+ @named_directories.clear
162
+
163
+ end
164
+
165
+ ##################################
166
+ # self.load_configuration_file #
167
+ ##################################
168
+
169
+ ###
170
+ # Load configuration file.
171
+ # Looks first in project directory, second in home directory.
172
+ # If configuration file is not found in project directory, Development will not load.
173
+ #
174
+ def self.load_configuration_file( path )
175
+
176
+ # we build up a configuration line and process when we reach its end (the next line)
177
+ expression_string = ''
178
+
179
+ configuration_file_path = ::File.expand_path( path )
180
+
181
+ @line_number = 0
182
+
183
+ ::File.open( configuration_file_path ).each_with_index do |this_line, this_line_number|
184
+
185
+ # when parse_configuration_file_line returns false we have a complete expression
186
+ while parse_configuration_file_line( expression_string, this_line )
187
+
188
+ # process expression_string
189
+ parse_configuration_expression( expression_string )
190
+
191
+ # reset expression_string
192
+ expression_string.clear
193
+
194
+ # update line number where expression begins
195
+ @line_number = this_line_number
196
+ unless this_line.empty?
197
+ @line_number += 1
198
+ end
199
+
200
+ # loop will cause start with this_line, which told parse_configuration_file_line
201
+ # that we were done, and which is therefore not yet processed
202
+
203
+ end
204
+
205
+ end
206
+
207
+ parse_configuration_expression( expression_string )
208
+
209
+ end
210
+
211
+ ########################################
212
+ # self.parse_configuration_file_line #
213
+ ########################################
214
+
215
+ ###
216
+ # Parses configuration_file_line to construct expression_string from multiple configuration_file_lines.
217
+ #
218
+ # @param expression_string
219
+ #
220
+ # Configuration expression that spans one or more lines in configuration file.
221
+ #
222
+ # @param configuration_file_line
223
+ #
224
+ # Literal line from configuration file (may only be part of an expression).
225
+ #
226
+ # @return [true,false] Whether expression is still complete.
227
+ # True means configuration_file_line was not processed.
228
+ #
229
+ def self.parse_configuration_file_line( expression_string, configuration_file_line, continuation = false )
230
+
231
+ expression_complete = false
232
+
233
+ # if we begin with a comment we can throw away the line
234
+ if configuration_file_line[ 0 ] == '#'
235
+
236
+ # nothing to do - we just ignore the line
237
+
238
+ # if we begin with whitespace we have a continuation
239
+ elsif configuration_file_line[ 0 ] =~ /\s/
240
+
241
+ configuration_file_line.strip!
242
+
243
+ expression_complete = parse_configuration_file_line( expression_string, configuration_file_line, true )
244
+
245
+ elsif continuation
246
+
247
+ unless expression_string.empty?
248
+ unless configuration_file_line.empty?
249
+ expression_string << ' '
250
+ end
251
+ end
252
+ expression_string << configuration_file_line.strip
253
+
254
+ elsif expression_string.empty?
255
+
256
+ expression_string.replace( configuration_file_line.strip )
257
+
258
+ # otherwise we reached the next line of the configuration file
259
+ else
260
+
261
+ expression_complete = true
262
+
263
+ end
264
+
265
+ return expression_complete
266
+
267
+ end
268
+
269
+ #########################################
270
+ # self.parse_configuration_expression #
271
+ #########################################
272
+
273
+ ###
274
+ # Parse single configuration expression built up from one or more actual configuration file lines.
275
+ #
276
+ # @param expression_string
277
+ #
278
+ # String describing configuration directive.
279
+ #
280
+ # @return [Object] self.
281
+ #
282
+ def self.parse_configuration_expression( expression_string )
283
+
284
+ case expression_string[ 0 ]
285
+
286
+ # + - named directory expression
287
+ when '+'
288
+
289
+ # either a directory definition or a general directory directive
290
+ # directory definitions are multiplart, whereas general directory definitions are one part
291
+ parse_named_directory_expression( expression_string )
292
+
293
+ # - - remove general path
294
+ when '-'
295
+
296
+ parse_remove_general_load_path_expression( expression_string )
297
+
298
+ # = - gemset expression
299
+ when '='
300
+
301
+ parse_gemset_expression( expression_string )
302
+
303
+ # @ - location expression
304
+ when '@'
305
+
306
+ parse_general_directory_or_location_expression( expression_string )
307
+
308
+ # ! - enable/disable expression
309
+ when '!'
310
+
311
+ parse_enable_disable_expression( expression_string )
312
+
313
+ # general path expression
314
+ else
315
+
316
+ parse_general_load_path_expression( expression_string )
317
+
318
+ end
319
+
320
+ return self
321
+
322
+ end
323
+
324
+ #########################################################
325
+ # self.parse_general_directory_or_location_expression #
326
+ #########################################################
327
+
328
+ ###
329
+ # Parse expression string that has been determined as either a general path or location expression.
330
+ #
331
+ # @param expression_string
332
+ #
333
+ # String describing general path or location expression.
334
+ #
335
+ # @return [Object] Self.
336
+ #
337
+ def self.parse_general_directory_or_location_expression( expression_string )
338
+
339
+ # if we have multiple parts
340
+ if whitespace_index = expression_string =~ /\s/
341
+
342
+ parse_location_expression( expression_string )
343
+
344
+ # if we have one part
345
+ else
346
+
347
+ parse_general_load_path_expression( expression_string )
348
+
349
+ end
350
+
351
+ return self
352
+
353
+ end
354
+
355
+ ###########################################
356
+ # self.parse_named_directory_expression #
357
+ ###########################################
358
+
359
+ ###
360
+ # Parse expression string that has been determined as a named directory expression.
361
+ #
362
+ # @param expression_string
363
+ #
364
+ # String describing named directory expression.
365
+ #
366
+ # @return [Object] Self.
367
+ #
368
+ def self.parse_named_directory_expression( expression_string )
369
+
370
+ # +directory_name path
371
+
372
+ unless whitespace_index = expression_string =~ /\s/
373
+ raise Exception::MalformedExpression::
374
+ MalformedNamedDirectoryExpression.new( expression_string, @line_number )
375
+ end
376
+
377
+ directory_name = expression_string.slice( 1, whitespace_index - 1 )
378
+ slice_length = expression_string.length - whitespace_index
379
+ path = expression_string.slice( whitespace_index + 1, slice_length ).strip
380
+
381
+ case path[0]
382
+ when '@'
383
+ path_parts = path.split( '/' )
384
+ named_path_name = path_parts.shift
385
+ named_path_name.slice!( 0, 1 )
386
+ path = ::File.join( directory( named_path_name ), path_parts )
387
+ end
388
+
389
+ @named_directories[ directory_name.to_sym ] = ::File.expand_path( path )
390
+
391
+ return self
392
+
393
+ end
394
+
395
+ ##################################
396
+ # self.parse_gemset_expression #
397
+ ##################################
398
+
399
+ ###
400
+ # Parse expression string that has been determined as a gemset expression.
401
+ #
402
+ # @param expression_string
403
+ #
404
+ # String describing gemset expression.
405
+ #
406
+ # @return [Object] Self.
407
+ #
408
+ def self.parse_gemset_expression( expression_string )
409
+
410
+ # =gemset gem_or_set_name[,] ...
411
+ # =gemset +gem_or_set_name[,] ...
412
+ # =gemset -gem_or_set_name[,] ...
413
+
414
+ gemset_name = parse_base_action_from_expression_string( expression_string )
415
+
416
+ gemset = create_gemset( gemset_name )
417
+
418
+ parse_gem_names_from_expression_string( gemset, expression_string )
419
+
420
+ return self
421
+
422
+ end
423
+
424
+ ###################################################
425
+ # self.parse_base_action_from_expression_string #
426
+ ###################################################
427
+
428
+ def self.parse_base_action_from_expression_string( expression_string )
429
+
430
+ base_action = nil
431
+
432
+ # get rid of =
433
+ expression_string.slice!( 0, 1 )
434
+
435
+ if whitespace_index = expression_string =~ /\s/
436
+ base_action = expression_string.slice!( 0, whitespace_index )
437
+ else
438
+ base_action = expression_string.dup
439
+ expression_string.clear
440
+ end
441
+
442
+ expression_string.strip!
443
+
444
+ return base_action
445
+
446
+ end
447
+
448
+ #################################################
449
+ # self.parse_gem_names_from_expression_string #
450
+ #################################################
451
+
452
+ def self.parse_gem_names_from_expression_string( array, expression_string, require_exist = false )
453
+
454
+ while next_whitespace_index = expression_string =~ /\s/
455
+ parse_gem_name_from_expression_string( array, expression_string, next_whitespace_index )
456
+ end
457
+
458
+ # also slice till the end
459
+ parse_gem_name_from_expression_string( array, expression_string, expression_string.length, require_exist )
460
+
461
+ end
462
+
463
+ ################################################
464
+ # self.parse_gem_name_from_expression_string #
465
+ ################################################
466
+
467
+ ###
468
+ # Helper method to slice gem name from expression string and add or subtract from gemset.
469
+ #
470
+ # @param gemset
471
+ #
472
+ # Gemset instance.
473
+ #
474
+ # @param expression_string
475
+ #
476
+ # Expression string.
477
+ #
478
+ # @param slice_to_index
479
+ #
480
+ # Index to slice expression string to.
481
+ #
482
+ def self.parse_gem_name_from_expression_string( array, expression_string, slice_to_index, require_exist = false )
483
+
484
+ gem_name = expression_string.slice!( 0, slice_to_index )
485
+
486
+ unless gem_name.empty?
487
+
488
+ case gem_name[ -1 ]
489
+ when ','
490
+ gem_name.slice!( -1, 1 )
491
+ end
492
+
493
+ should_add = true
494
+
495
+ case gem_name[ 0 ]
496
+ when '+'
497
+ gem_name.slice!( 0, 1 )
498
+ when '-'
499
+ gem_name.slice!( 0, 1 )
500
+ array.delete( gem_name.to_sym )
501
+ should_add = false
502
+ else
503
+ end
504
+
505
+ # ensure we have 'gem-subname' rather than 'gem/subname'
506
+ # we really just need one or the other consistently
507
+ gem_name.gsub!( '/', '-' )
508
+
509
+ gem_name = gem_name.to_sym
510
+
511
+ if require_exist
512
+ unless @enabled_gems.has_key?( gem_name ) or
513
+ @disabled_gems.has_key?( gem_name ) or
514
+ @gemsets.has_key?( gem_name)
515
+ raise Exception::ExpressionError::UnknownGemOrGemsetName.new( gem_name, @line_number )
516
+ end
517
+ end
518
+
519
+ if should_add
520
+ array.push( gem_name )
521
+ end
522
+
523
+ expression_string.strip!
524
+
525
+ end
526
+
527
+ return gem_name
528
+
529
+ end
530
+
531
+ ########################
532
+ # self.create_gemset #
533
+ ########################
534
+
535
+ def self.create_gemset( gemset_name )
536
+
537
+ gemset_name = gemset_name.to_sym
538
+
539
+ unless gemset = @gemsets[ gemset_name ]
540
+ @gemsets[ gemset_name ] = gemset = ::Array::Unique.new
541
+ end
542
+
543
+ return gemset
544
+
545
+ end
546
+
547
+ #################
548
+ # self.gemset #
549
+ #################
550
+
551
+ def self.gemset( gemset_name )
552
+
553
+ return @gemsets[ gemset_name.to_sym ]
554
+
555
+ end
556
+
557
+ ####################################
558
+ # self.parse_location_expression #
559
+ ####################################
560
+
561
+ ###
562
+ # Parse expression string that has been determined as a location expression.
563
+ #
564
+ # @param expression_string
565
+ #
566
+ # String describing location expression.
567
+ #
568
+ # @return [Object] Self.
569
+ #
570
+ def self.parse_location_expression( expression_string )
571
+
572
+ # @directory_name gem_or_set_name[,] ...
573
+
574
+ directory_name = parse_base_action_from_expression_string( expression_string )
575
+
576
+ directory_name = directory_name.to_sym
577
+
578
+ unless @named_directories.has_key?( directory_name )
579
+ raise Exception::MalformedExpression::UnknownDirectoryName.new( directory_name, @line_number )
580
+ end
581
+
582
+ unless directory_members = @locations[ directory_name ]
583
+ @locations[ directory_name ] = directory_members = ::Array::Unique.new
584
+ end
585
+
586
+ parse_gem_names_from_expression_string( directory_members, expression_string )
587
+
588
+ directory_members.each do |this_gem_or_gemset|
589
+ if gemset = @gemsets[ this_gem_or_gemset ]
590
+ gemset.each do |this_gem|
591
+ @gem_locations[ this_gem ] = directory_name
592
+ end
593
+ else
594
+ @gem_locations[ this_gem_or_gemset ] = directory_name
595
+ end
596
+ end
597
+
598
+ return self
599
+
600
+ end
601
+
602
+ ##########################################
603
+ # self.parse_enable_disable_expression #
604
+ ##########################################
605
+
606
+ ###
607
+ # Parse expression string that has been determined as a enable/disable expression.
608
+ #
609
+ # @param expression_string
610
+ #
611
+ # String describing enable/disable expression.
612
+ #
613
+ # @return [Object] Self.
614
+ #
615
+ def self.parse_enable_disable_expression( expression_string )
616
+
617
+ # !enable
618
+ # !disable
619
+ # !enable gem_or_set_name[,] ...
620
+ # !disable gem_or_set_name[,] ...
621
+
622
+ # enable or disable
623
+ enable_or_disable = parse_base_action_from_expression_string( expression_string )
624
+
625
+ gems = nil
626
+ unless expression_string.empty?
627
+ gems = ::Array::Unique.new
628
+ parse_gem_names_from_expression_string( gems, expression_string )
629
+ end
630
+
631
+ case enable_or_disable = enable_or_disable.to_sym
632
+
633
+ when :enable
634
+
635
+ if gems
636
+ gems.each do |this_gem, true_value|
637
+ @enabled_gems.push( this_gem )
638
+ @disabled_gems.delete( this_gem )
639
+ end
640
+ else
641
+ @disabled_gems.delete_if do |this_gem, true_value|
642
+ @enabled_gems.push( this_gem )
643
+ true
644
+ end
645
+ @enable_for_all = true
646
+ end
647
+
648
+ when :disable
649
+
650
+ if gems
651
+ gems.each do |this_gem, true_value|
652
+ @disabled_gems.push( this_gem )
653
+ @enabled_gems.delete( this_gem )
654
+ end
655
+ else
656
+ @enabled_gems.delete_if do |this_gem, true_value|
657
+ @disabled_gems.push( this_gem )
658
+ true
659
+ end
660
+ @enable_for_all = false
661
+ end
662
+
663
+ end
664
+
665
+ # do we have gems?
666
+
667
+ return self
668
+
669
+ end
670
+
671
+ #############################################
672
+ # self.parse_general_load_path_expression #
673
+ #############################################
674
+
675
+ ###
676
+ # Parse expression string that has been determined as a general directory expression.
677
+ #
678
+ # @param expression_string
679
+ #
680
+ # String describing general directory expression.
681
+ #
682
+ # @return [Object] Self.
683
+ #
684
+ def self.parse_general_load_path_expression( expression_string )
685
+
686
+ # path/to/directory, ~/path/to/directory, /path/to/directory
687
+ # +directory_name/path/from/directory
688
+
689
+ case expression_string[ 0 ]
690
+
691
+ when '@'
692
+
693
+ path_parts = expression_string.split( '/' )
694
+ named_directory = path_parts.shift
695
+ named_directory.slice!( 0, 1 )
696
+ named_directory = named_directory.to_sym
697
+ expression_string = ::File.expand_path( ::File.join( directory( named_directory ), path_parts ) )
698
+
699
+ end
700
+
701
+ @general_load_paths.push( ::File.expand_path( expression_string ) )
702
+
703
+ return self
704
+
705
+ end
706
+
707
+ ####################################################
708
+ # self.parse_remove_general_load_path_expression #
709
+ ####################################################
710
+
711
+ ###
712
+ # Parse expression string that has been determined as a remove-general-directory expression.
713
+ #
714
+ # @param expression_string
715
+ #
716
+ # String describing remove general directory expression.
717
+ #
718
+ # @return [Object] Self.
719
+ #
720
+ def self.parse_remove_general_load_path_expression( expression_string )
721
+
722
+ # -path/to/directory, -~/path/to/directory, -/path/to/directory
723
+
724
+ expression_string.slice!( 0, 1 )
725
+ path_string = expression_string.dup
726
+ expression_string.clear
727
+
728
+ @general_load_paths.delete( ::File.expand_path( path_string ) )
729
+
730
+ return self
731
+
732
+ end
733
+
734
+ ##################
735
+ # self.require #
736
+ ##################
737
+
738
+ ###
739
+ # Filters requires to match configuration specifications for loading development paths instead of production gems.
740
+ #
741
+ # @param gem_name_or_path
742
+ #
743
+ # Gem name or path to file passed to {::Object#require}.
744
+ #
745
+ # @return [true,false] Whether Development handled gem_name_or_path (true) or processing should continue (false).
746
+ #
747
+ def self.require( gem_name_or_path )
748
+
749
+ did_load = false
750
+
751
+ # if our path ends with an extension we are not requiring a gem and thus not responsible for managing it
752
+ if ::File.extname( gem_name_or_path ).empty?
753
+
754
+ gem_name = gem_name_or_path.to_s
755
+
756
+ # ensure we have 'gem-subname' rather than 'gem/subname'
757
+ # we really just need one or the other consistently
758
+ gem_directory_name = gem_name.gsub( '/', '-' )
759
+
760
+ # look for gem name in enabled gems/gemsets
761
+ if @enabled_gems.include?( gem_name.to_sym ) or
762
+ @enable_for_all && ! @disabled_gems.include?( gem_name.to_sym )
763
+
764
+ if directory_name = @gem_locations[ gem_name.to_sym ] and
765
+ load_path = directory( directory_name ) and
766
+ gem_name_at_load_path?( load_path, gem_directory_name, true )
767
+
768
+ load_gem_from_path( load_path, gem_directory_name )
769
+ did_load = true
770
+
771
+ else
772
+ # look in each path for gem - use first to match
773
+ @general_load_paths.each do |this_load_path|
774
+
775
+ # look for gem name at load path
776
+ if gem_name_at_load_path?( this_load_path, gem_name )
777
+ load_gem_from_path( this_load_path, gem_name )
778
+ did_load = true
779
+ end
780
+
781
+ end
782
+
783
+ end
784
+
785
+ end
786
+
787
+ end
788
+
789
+ return did_load
790
+
791
+ end
792
+
793
+ #################################
794
+ # self.gem_name_at_load_path? #
795
+ #################################
796
+
797
+ ###
798
+ # Query whether gem name is present at load path.
799
+ #
800
+ # @param load_path
801
+ #
802
+ # Path where gem directory might be located.
803
+ #
804
+ # @param gem_directory_name
805
+ #
806
+ # Name of gem. Assumes gem-subname is used rather than gem/subname.
807
+ #
808
+ # @return [true,false] Whether gem name is present.
809
+ #
810
+ def self.gem_name_at_load_path?( load_path, gem_directory_name, require_gem_at_path = false )
811
+
812
+ exists_at_load_path = false
813
+
814
+ gem_name = gem_directory_name.gsub( '-', '/' )
815
+ gem_path = ::File.join( load_path, gem_directory_name )
816
+
817
+ gem_require_file = ::File.join( gem_path, 'lib', gem_name ) + '.rb'
818
+
819
+ if ::Dir.exist?( ::File.expand_path( gem_path ) ) and
820
+ ::File.exist?( ::File.expand_path( gem_require_file ) )
821
+
822
+ exists_at_load_path = true
823
+
824
+ end
825
+
826
+ return exists_at_load_path
827
+
828
+ end
829
+
830
+ #############################
831
+ # self.load_gem_from_path #
832
+ #############################
833
+
834
+ ###
835
+ # Load gem from gem path. Assumes gem is present at path.
836
+ #
837
+ # @param load_path
838
+ #
839
+ # Path where gem directory might be located.
840
+ #
841
+ # @param gem_directory_name
842
+ #
843
+ # Name of gem. Assumes gem-subname is used rather than gem/subname.
844
+ #
845
+ # @return [true,false] Whether gem name is present.
846
+ #
847
+ def self.load_gem_from_path( load_path, gem_directory_name )
848
+
849
+ gem_name = gem_directory_name.gsub( '-', '/' )
850
+ gem_path = ::File.join( load_path, gem_directory_name )
851
+
852
+ gem_require_file = ::File.join( gem_path, 'lib', gem_name ) + '.rb'
853
+
854
+ require_relative( ::File.expand_path( gem_require_file ) )
855
+
856
+ end
857
+
858
+ end
859
+
860
+ require_relative 'development/require.rb'
861
+
862
+ require_relative 'development/exception/expression_error.rb'
863
+ require_relative 'development/exception/expression_error/unknown_directory_name.rb'
864
+ require_relative 'development/exception/expression_error/unknown_gem_or_gemset_name.rb'
865
+
866
+ require_relative 'development/exception/malformed_expression.rb'
867
+ require_relative 'development/exception/malformed_expression/malformed_named_directory_expression.rb'
868
+ require_relative 'development/exception/malformed_expression/malformed_gemset_expression.rb'
869
+ require_relative 'development/exception/malformed_expression/malformed_location_expression.rb'
870
+ require_relative 'development/exception/malformed_expression/malformed_enable_disable_expression.rb'
871
+ require_relative 'development/exception/malformed_expression/malformed_general_directory_expression.rb'
872
+ require_relative 'development/exception/malformed_expression/malformed_remove_general_directory_expression.rb'
873
+
874
+ ###
875
+ # Object is enabled with Development require functionality.
876
+ #
877
+ class ::Object
878
+ include ::Development::Require
879
+ end
880
+
881
+ #::Development.load_configuration_file( ::File.join( '~', ConfigurationFileName ) )