jackbox 0.9.6.2 → 0.9.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +13 -5
- data/CHANGES.txt +41 -1
- data/LICENSE.lic +0 -0
- data/README.md +244 -149
- data/Rakefile +6 -6
- data/jackbox.gemspec +3 -2
- data/lib/jackbox.rb +1 -1
- data/lib/jackbox/injectors.rb +1 -1
- data/lib/jackbox/rake.rb +1 -1
- data/lib/jackbox/tools/prefs.rb +1 -1
- data/lib/jackbox/version.rb +1 -1
- data/spec/lib/abtract_spec.rb +6 -6
- data/spec/lib/jackbox/injector_composition_spec.rb +106 -88
- data/spec/lib/jackbox/injector_directives_spec.rb +46 -0
- data/spec/lib/jackbox/injector_inheritance_spec.rb +980 -410
- data/spec/lib/jackbox/injector_introspection_spec.rb +333 -208
- data/spec/lib/jackbox/injector_spec.rb +28 -28
- data/spec/lib/jackbox/injector_versioning_spec.rb +1 -0
- data/spec/lib/jackbox/patterns_spec.rb +146 -14
- data/spec/lib/jackbox/reclassing_spec.rb +165 -78
- data/spec/lib/jackbox/vmc_spec.rb +246 -0
- metadata +32 -28
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,15 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
             | 
| 2 | 
            +
            !binary "U0hBMQ==":
         | 
| 3 | 
            +
              metadata.gz: !binary |-
         | 
| 4 | 
            +
                NmRkNTJhNTE1MDYyNjZhNjg3OTJlNzc5NTRiNzU3ZDVhNmE4ZTMzZA==
         | 
| 5 | 
            +
              data.tar.gz: !binary |-
         | 
| 6 | 
            +
                NTJlZWM5NGJkZTA2YzA3NWJlY2RmMDY3NTc0NzE3ODJmODg3MzgzMw==
         | 
| 5 7 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
             | 
| 8 | 
            +
              metadata.gz: !binary |-
         | 
| 9 | 
            +
                YTc1M2M2MGZjMzIzMDMxYWExMzgyNGU2MjQyYTMxZGZiMzNiZGJmMWU3ZmEx
         | 
| 10 | 
            +
                N2M4YTg5ZmU5MWFlM2NhMzUxOTNlZWU5OTM1NGRjZTE5MTM0MjIzNjQ4Mjc4
         | 
| 11 | 
            +
                NDdmM2M1ZDc4YzFjM2QyODY5NWJmMzQzOWFhNjczZmYwMjdjZTI=
         | 
| 12 | 
            +
              data.tar.gz: !binary |-
         | 
| 13 | 
            +
                MzE0MGI3Zjg1ZGRmNzNjZTM0OTM0MGZlMGI3YTgzOTMwNjI5MjQzOTllMDVk
         | 
| 14 | 
            +
                ZjQ0NjJmYWYzYWU3NDZkMWM5NTliNjA1NWI2MzZlZDQ2ZGFkNjg5NTZjMDU5
         | 
| 15 | 
            +
                YmUxNmUxZDBmNjdkMzYwM2QzZWExMjhjOGE4MmFkNDNhMjg0NWY=
         | 
    
        data/CHANGES.txt
    CHANGED
    
    | @@ -1,4 +1,44 @@ | |
| 1 | 
            -
            0.9. | 
| 1 | 
            +
            0.9.6.3  RC2
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Cleaned up inheritance, vmc, and patterns examples.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            . Got re-classes working with rspec 3.4
         | 
| 6 | 
            +
            . Changed the jack #inspect method. Cleaned up examples
         | 
| 7 | 
            +
            . Fixed singleton class duping and cloning issues
         | 
| 8 | 
            +
            . Concluded some VMC changes expanding its reach
         | 
| 9 | 
            +
              . Fixed issue with method_missing blocking
         | 
| 10 | 
            +
            . Converted the order injectors get added and reported
         | 
| 11 | 
            +
              . now they follow the Ruby lead with precedence from right to left
         | 
| 12 | 
            +
            . Introduced Just-In-Time Inheritance
         | 
| 13 | 
            +
              . inheritance works by compiling ancestors just in time of when used
         | 
| 14 | 
            +
            . Extended inheritance examples to include more lifecycle events
         | 
| 15 | 
            +
            . Finalized the specification of Introspection
         | 
| 16 | 
            +
            . Reached a more refined implementation of equality
         | 
| 17 | 
            +
            . Added more inheritance examples and improved others
         | 
| 18 | 
            +
            . Fixed an issue with JIT inheritance overriding every other inclusion
         | 
| 19 | 
            +
            . Optimized  tag tracing and un-hosted injector deletion
         | 
| 20 | 
            +
            . Reworked some introspection examples
         | 
| 21 | 
            +
            . Added include inheritance example to patterns
         | 
| 22 | 
            +
            . Fixed some #with subtleties:
         | 
| 23 | 
            +
              . include now works on modules
         | 
| 24 | 
            +
              . temp fix to issue with 1.9 and 2.xx
         | 
| 25 | 
            +
            . Added Re-Classes and examples
         | 
| 26 | 
            +
            . Fixed a couple issues with re-classes and standard types
         | 
| 27 | 
            +
            . Added longer decorator examples illustrating their use with Web Technologies
         | 
| 28 | 
            +
            . Optimized some issues
         | 
| 29 | 
            +
            . Fixed wrong evaluation of blocks for Tags on include/extend
         | 
| 30 | 
            +
            . Fixed extend/inject call on injectors not evaluating correctly
         | 
| 31 | 
            +
            . Reworked Lets
         | 
| 32 | 
            +
            . Eliminated all un-necessary nil testing. 
         | 
| 33 | 
            +
              . only left on :collapse/:silence directives and couple others.
         | 
| 34 | 
            +
            . Fixed some performance issues with Ruby 1.9.3 and Tag naming
         | 
| 35 | 
            +
            . Fixed #progenitor and #lineage
         | 
| 36 | 
            +
            . Fixed precedent
         | 
| 37 | 
            +
            . Cleaned up code and examples
         | 
| 38 | 
            +
            . Updated Readme
         | 
| 39 | 
            +
             | 
| 40 | 
            +
             | 
| 41 | 
            +
            0.9.5.9  RC1
         | 
| 2 42 |  | 
| 3 43 | 
             
            . Added a spec for Injector behavior under Inheritance
         | 
| 4 44 | 
             
            . Fixed problem with same method name object level class ejection
         | 
    
        data/LICENSE.lic
    CHANGED
    
    | Binary file | 
    
        data/README.md
    CHANGED
    
    | @@ -16,19 +16,23 @@ Copyright © 2014, 2015 LHA. All rights reserved. | |
| 16 16 | 
             
            <a href="http://jackbox.us"><h1>Jackbox</h1></a>
         | 
| 17 17 |  | 
| 18 18 | 
             
            ---
         | 
| 19 | 
            -
            <h2 style="font-family: | 
| 20 | 
            -
             | 
| 21 | 
            -
            The defining  | 
| 19 | 
            +
            <h2 style="font-family:Impact">Ruby Modular Closures, Code Injectors, Re-Classes and other programmer morphins</h2>
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            The defining thought behind Jackbox is a single and powerful one: If Ruby is like Play-Doh, with Jackbox we want to turn it into <a href="https://en.wikipedia.org/wiki/Plasticine">Plasticine</a>.  The library functions at this time take this idea and materialize it around the concepts of code injectors, re-classes, the application of versioning to runtimes, and a just-in-time inheritance model that together with the helper functions that bring them together, provide some new and interesting capabilities.  
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            To make it easier to grasp, code injectors can perhaps be thought of as a form of **Modular Closures©** or of **closures which can also serve as modules**.  These modular closures most of all propose some additional properties to the idea of a mix-in.  For instance, they make it possible to solve several general problems in some areas of OOP, overcoming traditional Ruby shortcomings with the GOF Decorator and Strategy Patterns, and enabling **some new code patterns** of our own.  They instrument control over (code presence) the presence of injector code in targets with mechanisms involving injector ejection and directives.  They give your code the ability to capture its surrounding context and mix it into an indiscriminate target. They extend Ruby's mix-in and method resolution over and beyond what is possible with regular modules. 
         | 
| 22 24 |  | 
| 23 | 
            -
             | 
| 25 | 
            +
            Re-classes on the other hand present an alternative way to refine a class.  They provide similar benefits to refinements with a different underpinning. Together with Jackbox code injectors and helper functions, re-classes can be refined multiple times.  Capabilities can be added and removed in blocks.  Moreover, these re-classes acquire introspecting abilities.  A re-class can be tested for existence, can tell you what injectors it uses, and finally can be overridden with a more relevant one. 
         | 
| 24 26 |  | 
| 25 | 
            -
             | 
| 27 | 
            +
            Following on this we introduce the concept of Injector Versioning.  This is a feature which allows you to redefine parts of your program in local isolation and without it affecting others.  See Injector Versioning below. Runtimes can morph their capabilities as they learn about themselves, and they can do so in blocks as granular or as coarse as needed.  These blocks can be updated, ejected, silenced, or re-injected with more function. This versioning also provides a form of inheritance.  We have called this Versioned Inheritance and it allows newer versions to inherit from previous ones, be tagged and labeled, and this way be capable of reuse.  All this is further enhanced by the ability to resolve methods in more ways than regular Ruby modules can through the use of the VMC (Virtual Method Cache). See below.
         | 
| 26 28 |  | 
| 27 | 
            -
             | 
| 29 | 
            +
            Finally, we also present for the first time in our history the concept of Just-In-Time Inheritance.  This is a feature which allows the introduction of an ancestor hierarchy similar to what you find in Ruby classes just as it is needed by your code.  With it you can override previous members of a tag and expect to have access to its super members as part of the call, just like you would with classes.  But, this inheritance is all going on in the mix-in, the modular closure.  Families of injectors can be built with the use of this and the previous versioned inheritance, and can be readily applicable to any target.
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            We have chosen to keep the code obfuscated for now, to protect our intellectual property.  But, as our business model evolves we will be considering open sourcing it.  Our guiding principle through out it all has been keeping new constructs to a minimum.  We take an outer minimalistic approach that in reality takes a lot more behind the scenes to make things work.  Simplicity takes a lot.  We hope that all this work is to your liking.  
         | 
| 28 32 |  | 
| 29 33 | 
             
            Basic Methods
         | 
| 30 34 | 
             
            --------------------------
         | 
| 31 | 
            -
            There are some basic methods to Jackbox.  These are just rudimentary helpers, which in effect  | 
| 35 | 
            +
            There are some basic methods to Jackbox.  These are just rudimentary helpers, which in effect appear to be a form of syntax sugar for every day things.  But, behind their apparent sugar coating lie some additional capabilities as shown the deeper you delve into Jackbox.  For more on them read the following sections, but their preliminary descriptions follow here:
         | 
| 32 36 |  | 
| 33 37 | 
             
            #### #decorate :sym, &blk 
         | 
| 34 38 | 
             
            This method allows for decorations to be placed on a single method, be it an instance or class method without too much fuss. One important thing about #decorate is that it works like #define_method, but in addition, it also makes possible the use of Ruby's #super within the body of the decorator.  It really presents a better alternative and can be used instead of #alias\_method\_chain.
         | 
| @@ -66,7 +70,7 @@ It also works like so: | |
| 66 70 |  | 
| 67 71 |  | 
| 68 72 | 
             
            #### #with obj, &blk 
         | 
| 69 | 
            -
            There is also a new version of the #with construct.  The important thing to remember about #with is it has a primary context which is the object passed to it, and a secondary context which is the object you are making the call from.  This allows you to work **with** both contexts at the same time. The other important thing about #with is that it allows you to directly place definitions on and returns the same object you passed into it or the result of the last evaluation in the #with block.
         | 
| 73 | 
            +
            There is also a new version of the #with construct.  The important thing to remember about #with is it has a primary context which is the object passed to it, and a secondary context which is the object you are making the call from.  This allows you to work **with** both contexts at the same time. The other important thing about #with is that it allows you to directly place definitions on and returns the same object you passed into it, or the result of the last evaluation in the #with block.
         | 
| 70 74 |  | 
| 71 75 | 
             
            Here is some sample usage code:
         | 
| 72 76 |  | 
| @@ -128,7 +132,7 @@ Use it with **#decorate** on singleton classes like this: | |
| 128 132 |  | 
| 129 133 |  | 
| 130 134 | 
             
            #### #lets sym=nil, &blk 
         | 
| 131 | 
            -
            We could say, this is simple syntax sugar.  It adds readability to some constructs.  It allows the creation of local or global procs using a more  | 
| 135 | 
            +
            We could say, this is simple syntax sugar.  It adds readability to some constructs.  It allows the creation of local or global procs using a more friendly syntax. But #lets, also opens the door to a new coding pattern termed Re-Classes.  See below.  The important thing about #lets is that it always defines some lambda/proc/method.  It's use differs from that of #define_method in spirit, aside it use with respect to re-classes, #lets is mostly for one liners.  Here are some examples:
         | 
| 132 136 |  | 
| 133 137 | 
             
            To define local functions/lambdas. Define symbols in local scope:
         | 
| 134 138 |  | 
| @@ -155,7 +159,7 @@ Can be used to define a special values or pseudo-immutable strings: | |
| 155 159 |  | 
| 156 160 | 
             
            Injectors
         | 
| 157 161 | 
             
            ----------
         | 
| 158 | 
            -
            Injectors are the main tool in Jackbox at the time of this writing. These again are a form of mix-in that has properties of both a closure and a module.  They can also be thought of as an **extended closure** if you will or as a special kind of  | 
| 162 | 
            +
            Injectors are the main tool in Jackbox at the time of this writing. These again are a form of mix-in that has properties of both a closure and a module.  They can also be thought of as an **extended closure** if you will or as a special kind of mix-in if you want.  In the sections below we will discuss some of the methods available to you with Jackbox in connection with Injectors, as well as elaborate on some of the other properties of injectors. But, it is essential to understand there are some syntactical differences to Injectors with respect to regular modules.  We will show them first, with some examples: 
         | 
| 159 163 |  | 
| 160 164 | 
             
            **INJECTORS ARE DECLARED IN THE FOLLOWING WAYS:**
         | 
| 161 165 |  | 
| @@ -171,7 +175,7 @@ Injectors are the main tool in Jackbox at the time of this writing. These again | |
| 171 175 | 
             
                facet :Name                                    # capitalized method, using alias #facet 
         | 
| 172 176 |  | 
| 173 177 |  | 
| 174 | 
            -
            Their use and semantics are somewhat defined by the following snippet.  But, to fully understand their implications to your code, you have to understand the sections on injector versioning, their behavior under inheritance, and  | 
| 178 | 
            +
            Their use and semantics are somewhat defined by the following snippet.  But, to fully understand their implications to your code, you have to understand the sections on injector versioning, their behavior under inheritance, and also injector directives. 
         | 
| 175 179 |  | 
| 176 180 | 
             
                # somewhere in your code
         | 
| 177 181 | 
             
                include Injectors
         | 
| @@ -220,9 +224,11 @@ Their use and semantics are somewhat defined by the following snippet.  But, to | |
| 220 224 | 
             
                  end
         | 
| 221 225 |  | 
| 222 226 | 
             
                end
         | 
| 227 | 
            +
                
         | 
| 228 | 
            +
            These prolongations become versions when they are applied or when they are tagged.  See Tagging.
         | 
| 223 229 |  | 
| 224 230 | 
             
            #### #injector :sym
         | 
| 225 | 
            -
            This is a global function.  It defines an object of type Injector with the name of symbol.  Use it when you want to generate an Injector object for later use.  The symbol can then be used as a handle to the injector whenever you need to prolong the injector by adding methods to it or apply it to another object. Additionally, this symbol plays a role in defining the injector's scope.  Injectors with capitalized names like :Function, :Style, etc have a global scope.  That is they are available throughout the program:
         | 
| 231 | 
            +
            This is a global function.  It defines an object of type Injector with the name of symbol.  Use it when you want to generate an Injector object for later use.  The symbol can then be used as a handle to the injector whenever you need to prolong the injector by adding methods to it or apply it to another object to create a version. Additionally, this symbol plays a role in defining the injector's scope.  Injectors with capitalized names like :Function, :Style, etc have a global scope.  That is they are available throughout the program:
         | 
| 226 232 |  | 
| 227 233 | 
             
                class A
         | 
| 228 234 | 
             
                  injector :Function
         | 
| @@ -248,9 +254,9 @@ On the other hand Injectors with a lower case name are only available __from__ t | |
| 248 254 | 
             
                  include AA.form
         | 
| 249 255 | 
             
                end
         | 
| 250 256 |  | 
| 251 | 
            -
                # This is perfectly valid with injectors  
         | 
| 257 | 
            +
                # This is also perfectly valid with injectors  
         | 
| 252 258 |  | 
| 253 | 
            -
            For all this to happen Jackbox also introduces some additional Ruby constructs, namely the keywords #inject and #enrich.  These can be thought as simply new corollaries to #include and #extend. In fact they can be used interchangeably.  If you're working with injectors you may want to use them instead depending on context to make clear your intent.
         | 
| 259 | 
            +
            For all this to happen Jackbox also introduces some additional Ruby constructs, namely the keywords #inject and #enrich.  These can be thought as simply new corollaries to #include and #extend. In fact they can be used interchangeably.  If you're working with injectors you may want to use them instead depending on context to make clear your intent.  Also inject is public while include is not.
         | 
| 254 260 |  | 
| 255 261 | 
             
            #### #include/inject *jack
         | 
| 256 262 | 
             
            This method is analogous to ruby's #include but its use is reserved for Injectors.  The scope of this method is the same as the scope of #include, and its intended use like include's is for class definitions. Use it to "include" an Injector into a receiving class.  Takes multiple injectors.
         | 
| @@ -388,7 +394,7 @@ The use of Tags is central to the concept of Injector Versioning.  Tagging happe | |
| 388 394 | 
             
                  end
         | 
| 389 395 | 
             
                end
         | 
| 390 396 |  | 
| 391 | 
            -
            Version1 and Version2 are two different hard versions/tags | 
| 397 | 
            +
            Version1 and Version2 are two different hard versions/tags of the same Injector.  They introduce a more formal incantation of injector versioning and also pave the way for Versioned Inheritance as described in the introduction.  More on this below.  Aside from these hard tags, there are also soft tags (see below).  
         | 
| 392 398 |  | 
| 393 399 | 
             
            ### Local Binding
         | 
| 394 400 |  | 
| @@ -434,15 +440,15 @@ Before we move on, we also want to give some further treatment to injector local | |
| 434 440 | 
             
                ####################################################
         | 
| 435 441 |  | 
| 436 442 |  | 
| 437 | 
            -
            ### Method  | 
| 443 | 
            +
            ### Virtual Method Cache (VMC)
         | 
| 438 444 |  | 
| 439 | 
            -
            When you are working with an Injector in irb/pry it is often easier to just add methods to the injector without actually having to re-apply the injector to the the target to see the result.  This is just what the Jackbox  | 
| 445 | 
            +
            When you are working with an Injector in irb/pry it is often easier to just add methods to the injector without actually having to re-apply the injector to the the target to see the result.  This is just what the Jackbox Virtual Method Cache is for among other things.  Here is what the code looks like:
         | 
| 440 446 |  | 
| 441 | 
            -
                #  | 
| 447 | 
            +
                # definition
         | 
| 442 448 | 
             
                facet :SpecialMethods
         | 
| 443 449 |  | 
| 444 450 | 
             
                class MyClass
         | 
| 445 | 
            -
                  include SpecialMethods
         | 
| 451 | 
            +
                  include SpecialMethods                      # application with no methods
         | 
| 446 452 | 
             
                end
         | 
| 447 453 |  | 
| 448 454 | 
             
                obj = MyClass.new
         | 
| @@ -455,7 +461,31 @@ When you are working with an Injector in irb/pry it is often easier to just add | |
| 455 461 |  | 
| 456 462 | 
             
                expect(obj.spm1).to eq(:result)               # yet my obj can use it --no problem
         | 
| 457 463 |  | 
| 458 | 
            -
            The key idea here is that the method  | 
| 464 | 
            +
            The key idea here is that the virtual method cache is the same for all versions of the Injector and all its applications.  If we redefine those VMC methods they are also redefined for all versions.  To actually lock the method versions into place you must apply the Injector with the methods defined in it that you want the version to have.  The VMC also provides extended method resolution to the modular closure mix-in.  To understand what we mean by that take a look at following code:
         | 
| 465 | 
            +
             | 
| 466 | 
            +
                class Client
         | 
| 467 | 
            +
                  include jack :J1
         | 
| 468 | 
            +
                end
         | 
| 469 | 
            +
                J1 do
         | 
| 470 | 
            +
                	def n1m1
         | 
| 471 | 
            +
                	end
         | 
| 472 | 
            +
                  include facet :K1
         | 
| 473 | 
            +
                end
         | 
| 474 | 
            +
                K1 do
         | 
| 475 | 
            +
                	def n2m1
         | 
| 476 | 
            +
                	end
         | 
| 477 | 
            +
                  include facet :L1
         | 
| 478 | 
            +
                end
         | 
| 479 | 
            +
                L1 do
         | 
| 480 | 
            +
                  def n3m1
         | 
| 481 | 
            +
                  end
         | 
| 482 | 
            +
                end
         | 
| 483 | 
            +
             | 
| 484 | 
            +
                Client.new.n1m1
         | 
| 485 | 
            +
                Client.new.n2m1
         | 
| 486 | 
            +
                Client.new.n3m1
         | 
| 487 | 
            +
                
         | 
| 488 | 
            +
            Think of how this would be different with regular modules.  For this to happen using regular Ruby modules K1 and L1 should have to be defined and included prior to their inclusion into our client.  And no it is not just a matter of moving the include to the beginning of each container.
         | 
| 459 489 |  | 
| 460 490 | 
             
            #### #define\_method sym, &blk
         | 
| 461 491 | 
             
            There is one more interesting property to method definition on Injectors however. The use of #define\_method to re-define methods in any prolongation updates the entire injector and all its versions.  This also preserves a fundamental tenet of injectors: take some local context, enclose it, and use the injector to introduce it to some indiscriminate target, and additionally has some other uses as we'll see with in our description of patterns and injector composition.  
         | 
| @@ -639,6 +669,79 @@ The #pro method is a little different.  It gets the version from which a particu | |
| 639 669 |  | 
| 640 670 | 
             
            For more on this see the rspec files.     
         | 
| 641 671 |  | 
| 672 | 
            +
            ### Injector Equality and Difference 
         | 
| 673 | 
            +
             | 
| 674 | 
            +
            Injectors can be compared.  This allows further introspection capabilities which can be used to determine if a certain piece of code possesses a certain block of capabilities, test if those are equal to some other component's capabilities, or test what the difference is.  It only follows that if injectors can be applied and withdrawn from any target we should be able to test for their similarities to other injectors.  Injector difference tests for the actual delta between injectors and returns and array with those differences.  Here is how equality is defined:
         | 
| 675 | 
            +
             | 
| 676 | 
            +
                # equality
         | 
| 677 | 
            +
                ######################################
         | 
| 678 | 
            +
                E().should == E()
         | 
| 679 | 
            +
                E().should == E().spec
         | 
| 680 | 
            +
             | 
| 681 | 
            +
                E(:tag).should == E()
         | 
| 682 | 
            +
                if ETag1 = E()
         | 
| 683 | 
            +
                	ETag1.should == E()
         | 
| 684 | 
            +
                end
         | 
| 685 | 
            +
                extend E()
         | 
| 686 | 
            +
                injectors.first.should == E()
         | 
| 687 | 
            +
             | 
| 688 | 
            +
             | 
| 689 | 
            +
                # ** definition **
         | 
| 690 | 
            +
                E() do
         | 
| 691 | 
            +
                	def foo                   
         | 
| 692 | 
            +
                	end
         | 
| 693 | 
            +
                end     
         | 
| 694 | 
            +
                # ** definition **
         | 
| 695 | 
            +
             | 
| 696 | 
            +
             | 
| 697 | 
            +
                # inequality
         | 
| 698 | 
            +
                ######################################
         | 
| 699 | 
            +
                E().should == E()
         | 
| 700 | 
            +
                ETag1.should_not == E()
         | 
| 701 | 
            +
                injectors.first.should_not == E()
         | 
| 702 | 
            +
             | 
| 703 | 
            +
                E(:tag).should == E()
         | 
| 704 | 
            +
                E().should_not == F()
         | 
| 705 | 
            +
             | 
| 706 | 
            +
             | 
| 707 | 
            +
            Here is how difference is defined:
         | 
| 708 | 
            +
             | 
| 709 | 
            +
                # Injector#diff returns an Array
         | 
| 710 | 
            +
                ######################################
         | 
| 711 | 
            +
                E().diff.class.should be(Array)
         | 
| 712 | 
            +
             | 
| 713 | 
            +
             | 
| 714 | 
            +
                # equality in the converse expression
         | 
| 715 | 
            +
                ######################################
         | 
| 716 | 
            +
                E().diff(E()).should be_empty  	
         | 
| 717 | 
            +
             | 
| 718 | 
            +
                # because
         | 
| 719 | 
            +
                E().should == E()         # like above
         | 
| 720 | 
            +
             | 
| 721 | 
            +
             | 
| 722 | 
            +
                # unless changed E()== E().pre or E().spec
         | 
| 723 | 
            +
                ######################################
         | 
| 724 | 
            +
                E().diff.should be_empty
         | 
| 725 | 
            +
             | 
| 726 | 
            +
                # because
         | 
| 727 | 
            +
                E().diff.should == E().diff(E().pre)        
         | 
| 728 | 
            +
                E().pre.should equal( E().spec )
         | 
| 729 | 
            +
                # and
         | 
| 730 | 
            +
                E().should == E().spec    # like above
         | 
| 731 | 
            +
             | 
| 732 | 
            +
             | 
| 733 | 
            +
                # unless there is a delta it cannot be loaded?
         | 
| 734 | 
            +
                ######################################
         | 
| 735 | 
            +
                E().diff.should_not be_loaded
         | 
| 736 | 
            +
             | 
| 737 | 
            +
                # because
         | 
| 738 | 
            +
                E().diff.delta.should be_empty
         | 
| 739 | 
            +
             | 
| 740 | 
            +
                # ....
         | 
| 741 | 
            +
                
         | 
| 742 | 
            +
                
         | 
| 743 | 
            +
            Again, for more on this see the rspec files.
         | 
| 744 | 
            +
             | 
| 642 745 | 
             
            ### Injector composition
         | 
| 643 746 | 
             
            The composition of multiple injectors into an object can be specified as follows:
         | 
| 644 747 |  | 
| @@ -728,14 +831,14 @@ More importantly though is the following: | |
| 728 831 | 
             
                	end                                     
         | 
| 729 832 | 
             
                end                                       
         | 
| 730 833 |  | 
| 731 | 
            -
                TapePlayer = player do                        #  | 
| 732 | 
            -
                	def play | 
| 834 | 
            +
                TapePlayer = player do                        # TapePlayer Tag
         | 
| 835 | 
            +
                	def play                                    # --inherirts #sound
         | 
| 733 836 | 
             
                		return 'Tape playing...' + sound()                          
         | 
| 734 837 | 
             
                	end                                     
         | 
| 735 838 | 
             
                end                                       
         | 
| 736 839 |  | 
| 737 | 
            -
                CDPlayer = player do                          #  | 
| 738 | 
            -
                	def play | 
| 840 | 
            +
                CDPlayer = player do                          # CDPlayer Tag
         | 
| 841 | 
            +
                	def play                                    # --also inherits #sound
         | 
| 739 842 | 
             
                		return 'CD playing...' + sound()
         | 
| 740 843 | 
             
                	end
         | 
| 741 844 | 
             
                end
         | 
| @@ -747,30 +850,84 @@ More importantly though is the following: | |
| 747 850 | 
             
                		play
         | 
| 748 851 | 
             
                	end
         | 
| 749 852 | 
             
                end
         | 
| 853 | 
            +
                
         | 
| 854 | 
            +
                # ...
         | 
| 855 | 
            +
             | 
| 856 | 
            +
                
         | 
| 857 | 
            +
            From all this, the important thing to take is that injectors provide a sort of versioned inheritance.  The version inherits all of the pre-existing methods from the injector and freezes that function.  We can either Tag/Name it of simply include/extend into a target but the function is frozen at that time.  Tags cannot be modified or more clearly shouldn't be modified.  Classes retain the frozen version of the injector until the time an update is made.  Of course, there is always #define\_method.   For more on all this see, the Rspec examples.
         | 
| 858 | 
            +
             | 
| 859 | 
            +
            ### JIT inheritance
         | 
| 860 | 
            +
             | 
| 861 | 
            +
            This flavor of the inheritance model allows our modular closures to have similar properties to the inheritance of classes.  With it you can expect to have access to its super members as part of the call, just like you would with classes. In addition to the inheritance resulting from versioning, JIT inheritance presents a more complete scenario adding color to the picture painted by code injectors.  The key takeaway here is this: Code Injectors are mix-ins that share a similar inheritance model with classes. You can version them to gain access to versioned inheritance or you can override its members to access an ancestor chain comprised of all previous tags.  As always we will use some example code to illustrate:
         | 
| 862 | 
            +
             | 
| 863 | 
            +
                # 
         | 
| 864 | 
            +
                # Our Modular Closure
         | 
| 865 | 
            +
                # 
         | 
| 866 | 
            +
                Tag1 = jack :Tagger do
         | 
| 867 | 
            +
                	def m1
         | 
| 868 | 
            +
                		1
         | 
| 869 | 
            +
                	end
         | 
| 870 | 
            +
            	
         | 
| 871 | 
            +
                	def m2
         | 
| 872 | 
            +
                		:m2
         | 
| 873 | 
            +
                	end
         | 
| 874 | 
            +
                end
         | 
| 750 875 |  | 
| 751 | 
            -
                 | 
| 752 | 
            -
             | 
| 876 | 
            +
                # 
         | 
| 877 | 
            +
                # Normal Versioned Injector inheritance
         | 
| 878 | 
            +
                # 
         | 
| 879 | 
            +
                Tagger do
         | 
| 880 | 
            +
                	def other  					
         | 
| 881 | 
            +
                		'other'						# -- same ancestors as before
         | 
| 882 | 
            +
                	end 								
         | 
| 753 883 | 
             
                end
         | 
| 754 884 |  | 
| 755 | 
            -
                 | 
| 756 | 
            -
                JukeBox.new.on.should == 'CD playing...Lets make some music'
         | 
| 757 | 
            -
                
         | 
| 758 | 
            -
                jack :speakers
         | 
| 885 | 
            +
                expect(Tagger().ancestors).to eql( [Tagger()] )
         | 
| 759 886 |  | 
| 760 | 
            -
                 | 
| 761 | 
            -
                	def sound                               
         | 
| 762 | 
            -
                		super + '...boom boom boom...'        
         | 
| 763 | 
            -
                	end                                     
         | 
| 764 | 
            -
                end                                       
         | 
| 765 | 
            -
                JukeBox.inject Bass
         | 
| 887 | 
            +
                # test it
         | 
| 766 888 |  | 
| 767 | 
            -
                 | 
| 768 | 
            -
                
         | 
| 769 | 
            -
            From all this, the important thing to take is that injectors provide a sort of versioned inheritance.  The version inherits all of the pre-existing methods from the injector and freezes that function.  We can either Tag/Name it of simply include/extend into a target but the function is frozen at that time.  Tags cannot be modified or more clearly shouldn't be modified.  Classes retain the frozen version of the injector until the time an update is made.  Of course, there is always #define\_method.   For more on all this see, the Rspec examples.
         | 
| 889 | 
            +
                o  = Object.new.extend(Tagger())
         | 
| 770 890 |  | 
| 891 | 
            +
                # inherited
         | 
| 892 | 
            +
                o.m1.should == 1
         | 
| 893 | 
            +
                o.m2.should == :m2
         | 
| 894 | 
            +
             | 
| 895 | 
            +
                # current
         | 
| 896 | 
            +
                o.other.should == 'other'
         | 
| 897 | 
            +
             | 
| 898 | 
            +
             | 
| 899 | 
            +
                #
         | 
| 900 | 
            +
                # JIT inheritance
         | 
| 901 | 
            +
                # 
         | 
| 902 | 
            +
                Tag2 = Tagger do
         | 
| 903 | 
            +
                	def m1							# The :m1 override invokes JIT inheritance
         | 
| 904 | 
            +
                		super + 1					# -- Tag1 is summoned into ancestor chain
         | 
| 905 | 
            +
                	end 								# -- allows the use of super
         | 
| 906 | 
            +
            	
         | 
| 907 | 
            +
                	def m3							
         | 
| 908 | 
            +
                		'em3'
         | 
| 909 | 
            +
                	end
         | 
| 910 | 
            +
                end
         | 
| 911 | 
            +
             | 
| 912 | 
            +
                # test it
         | 
| 913 | 
            +
             | 
| 914 | 
            +
                p = Object.new.extend(Tag2)
         | 
| 915 | 
            +
             | 
| 916 | 
            +
                # JIT inherited
         | 
| 917 | 
            +
                p.m1.should == 2
         | 
| 918 | 
            +
             | 
| 919 | 
            +
                # regular inheritance
         | 
| 920 | 
            +
                p.m2.should == :m2
         | 
| 921 | 
            +
                p.m3.should == 'em3'
         | 
| 922 | 
            +
                p.other.should == 'other'
         | 
| 923 | 
            +
             | 
| 924 | 
            +
                expect(Tagger().ancestors).to eql( [Tagger(), Tag1] )
         | 
| 925 | 
            +
                expect(Tag2.ancestors).to eql( [Tag2, Tag1] )
         | 
| 926 | 
            +
             | 
| 927 | 
            +
            For more on this please see the rspec files in the project page or on the gem itself.
         | 
| 771 928 |  | 
| 772 929 | 
             
            ---
         | 
| 773 | 
            -
            But, this is the basic idea here.  An extended closure which can be used as a mix-in, prolonged to add function, and versioned and  | 
| 930 | 
            +
            But, this is the basic idea here.  An extended closure which can be used as a mix-in, prolonged to add function, and versioned, tagged, and inherited to fit the purpose at hand. Using this approach Jackbox also goes on to solve the Decorator Pattern problem in the Ruby language.  
         | 
| 774 931 |  | 
| 775 932 | 
             
            ---
         | 
| 776 933 |  | 
| @@ -873,71 +1030,10 @@ Here it is removed after an #inject at the class level: | |
| 873 1030 | 
             
                expect{Home.new.fractal}.to raise_error
         | 
| 874 1031 |  | 
| 875 1032 |  | 
| 876 | 
            -
            The code for these examples makes use of the #eject method which is also opens the door to some additional functionality provided by injectors.  See the Strategy Pattern just below this.  
         | 
| 1033 | 
            +
            The code for these examples makes use of the #eject method which is also opens the door to some additional functionality provided by injectors.  See the Strategy Pattern just below this. It is important to keep in mind that ejection is "permanent" (not really, can always be re-injected) and that is more of its intent.  For temporary withdrawal of an injector you should use injector directives as shown below.
         | 
| 877 1034 |  | 
| 878 1035 | 
             
            #### #eject *sym
         | 
| 879 | 
            -
            This method ejects injector function from a single object or class.  It is in scope on any classes injected or enriched by an injector.   | 
| 880 | 
            -
             | 
| 881 | 
            -
            ### Injector Equality and Difference 
         | 
| 882 | 
            -
             | 
| 883 | 
            -
            Injectors can be compared.  This allows for further introspection capabilities which could be used to determine if a certain piece of code possesses a block of capabilities, test if those are equal to some other component's capabilities, or test what the difference is.  It only follows that if injectors can be applied and withdrawn from any target we should be able to test for their similarities to other injectors.  Here is how equality is defined:
         | 
| 884 | 
            -
             | 
| 885 | 
            -
                # Equality
         | 
| 886 | 
            -
                
         | 
| 887 | 
            -
                E().should == E()
         | 
| 888 | 
            -
                E().should_not == E().spec
         | 
| 889 | 
            -
             | 
| 890 | 
            -
                E(:tag).should == E()
         | 
| 891 | 
            -
                ETag1 = E()
         | 
| 892 | 
            -
                ETag1.should == E()
         | 
| 893 | 
            -
             | 
| 894 | 
            -
                extend E()
         | 
| 895 | 
            -
                injectors.first.should == E()
         | 
| 896 | 
            -
             | 
| 897 | 
            -
                E() do
         | 
| 898 | 
            -
                	def foo                   # ** definition **
         | 
| 899 | 
            -
                	end
         | 
| 900 | 
            -
                end     
         | 
| 901 | 
            -
             | 
| 902 | 
            -
                E().should == E()
         | 
| 903 | 
            -
                ETag1.should_not == E()
         | 
| 904 | 
            -
                injectors.first.should_not == E()
         | 
| 905 | 
            -
                E(:tag).should == E()
         | 
| 906 | 
            -
             | 
| 907 | 
            -
                E().should_not == F()
         | 
| 908 | 
            -
                
         | 
| 909 | 
            -
            Here is how difference is defined:
         | 
| 910 | 
            -
             | 
| 911 | 
            -
                # Difference
         | 
| 912 | 
            -
             | 
| 913 | 
            -
                E().diff.should_not be_empty
         | 
| 914 | 
            -
                # because
         | 
| 915 | 
            -
                E().should_not == E().spec      # like above        
         | 
| 916 | 
            -
             | 
| 917 | 
            -
             | 
| 918 | 
            -
                ##################################
         | 
| 919 | 
            -
                E().diff.should_not be_loaded
         | 
| 920 | 
            -
                # because
         | 
| 921 | 
            -
                E().diff.join.should be_empty
         | 
| 922 | 
            -
                E().diff.delta.should_not be_empty
         | 
| 923 | 
            -
             | 
| 924 | 
            -
             | 
| 925 | 
            -
                ##################################
         | 
| 926 | 
            -
                E().diff(E()).should be_empty  	
         | 
| 927 | 
            -
                # because
         | 
| 928 | 
            -
                E().should == E()               # like above
         | 
| 929 | 
            -
             | 
| 930 | 
            -
                ETag2 = E()
         | 
| 931 | 
            -
             | 
| 932 | 
            -
             | 
| 933 | 
            -
                ##################################
         | 
| 934 | 
            -
                E().diff(ETag2).should be_empty
         | 
| 935 | 
            -
                ETag2.diff(E()).should be_empty
         | 
| 936 | 
            -
                # because 
         | 
| 937 | 
            -
                ETag2.should == E() 						# like above
         | 
| 938 | 
            -
             | 
| 939 | 
            -
             | 
| 940 | 
            -
            Again, for more on this see the rspec files.
         | 
| 1036 | 
            +
            This method ejects injector function from a single object or class.  It is in scope on any classes injected or enriched by an injector.  Its effect is that of completely removing one of our modular closures from the ancestor chain.  Once this is done method calls on the injector will came back with an error.  There are other ways to control code presence in targets through the use of Injector Directives.  See below.  For more on this also see the rspec examples.
         | 
| 941 1037 |  | 
| 942 1038 | 
             
            ### Injector Directives
         | 
| 943 1039 | 
             
            Once you have an injector handle you can also use it to issue directives to the injector.  These directives can have a profound effect on your code.
         | 
| @@ -1140,6 +1236,8 @@ Just like hard tags above but a name is not needed: | |
| 1140 1236 | 
             
                    :foooooooo
         | 
| 1141 1237 | 
             
                  end
         | 
| 1142 1238 | 
             
                end
         | 
| 1239 | 
            +
                
         | 
| 1240 | 
            +
            Accessible through Injector#tags (an Array).  Also available **injector#tags.hard** and **injector#tags.soft**.
         | 
| 1143 1241 |  | 
| 1144 1242 | 
             
            ---
         | 
| 1145 1243 | 
             
            ### Patterns of a Different Flavor
         | 
| @@ -1233,62 +1331,59 @@ __3) The Transformer Pattern.-__  For a specific example of what can be accompli | |
| 1233 1331 |  | 
| 1234 1332 | 
             
            __4) The Re-Classing Pattern.-__  Our base method #lets has one more interesting use which allows for an alternative way to refine classes.  We have termed this Re-Classing.  Look at the following code:
         | 
| 1235 1333 |  | 
| 1236 | 
            -
             | 
| 1237 | 
            -
             | 
| 1238 | 
            -
                SR1 = jack :StringRefinements do
         | 
| 1239 | 
            -
                	lets String do
         | 
| 1240 | 
            -
                		with singleton_class do
         | 
| 1241 | 
            -
                			alias _new new
         | 
| 1242 | 
            -
                			def new *args, &code
         | 
| 1243 | 
            -
                				super(*args, &code) + ' is a special string'
         | 
| 1244 | 
            -
                			end
         | 
| 1245 | 
            -
                		end
         | 
| 1246 | 
            -
                	end
         | 
| 1247 | 
            -
                end
         | 
| 1248 | 
            -
             | 
| 1249 | 
            -
                class OurClass
         | 
| 1250 | 
            -
                	include SR1
         | 
| 1251 | 
            -
             | 
| 1252 | 
            -
                	def foo_bar
         | 
| 1253 | 
            -
                		String('foo and bar')
         | 
| 1254 | 
            -
                	end
         | 
| 1255 | 
            -
                end
         | 
| 1256 | 
            -
             | 
| 1257 | 
            -
                c = OurClass.new
         | 
| 1258 | 
            -
                c.foo_bar.class.should == String
         | 
| 1259 | 
            -
                c.foo_bar.should == 'foo and bar is a special string'
         | 
| 1260 | 
            -
             | 
| 1261 | 
            -
            		SR2 = StringRefinements do 										# New Version
         | 
| 1334 | 
            +
            		module Work
         | 
| 1262 1335 | 
             
            			lets String do
         | 
| 1263 | 
            -
            				def  | 
| 1264 | 
            -
            					super | 
| 1336 | 
            +
            				def self.new(*args)
         | 
| 1337 | 
            +
            					"+++#{super}+++"
         | 
| 1265 1338 | 
             
            				end
         | 
| 1266 1339 | 
             
            			end
         | 
| 1267 1340 | 
             
            		end
         | 
| 1341 | 
            +
            		
         | 
| 1342 | 
            +
            		class WorkAholic
         | 
| 1343 | 
            +
            			include Work
         | 
| 1344 | 
            +
            			
         | 
| 1345 | 
            +
            			def work_method
         | 
| 1346 | 
            +
            				String('Men-At-Work')
         | 
| 1347 | 
            +
            			end
         | 
| 1348 | 
            +
            		end
         | 
| 1349 | 
            +
            	
         | 
| 1350 | 
            +
            		str = WorkAholic.new.work_method              # Our String re-class
         | 
| 1351 | 
            +
            		str.should == '+++Men-At-Work+++'
         | 
| 1268 1352 |  | 
| 1269 | 
            -
            		 | 
| 1353 | 
            +
            		str = String.new('men-at-work')               # Regular String
         | 
| 1354 | 
            +
            		str = 'men-at-work'
         | 
| 1355 | 
            +
            		
         | 
| 1356 | 
            +
            		str = String('Men-At-Work')										# Regular Kernel version
         | 
| 1357 | 
            +
            		str = 'Men-At-Work'
         | 
| 1358 | 
            +
            		
         | 
| 1270 1359 |  | 
| 1271 | 
            -
             | 
| 1272 | 
            -
            		c.foo_bar.class.should == String
         | 
| 1360 | 
            +
            The important thing to remember here is that #String() is a method now. We can redefine it, name-space it, test for its presence, etc.  We can also use it to redefine the re-class's methods.  
         | 
| 1273 1361 |  | 
| 1362 | 
            +
                jack :Log do
         | 
| 1363 | 
            +
                	require 'logger'
         | 
| 1274 1364 |  | 
| 1275 | 
            -
             | 
| 1276 | 
            -
             | 
| 1277 | 
            -
             | 
| 1278 | 
            -
             | 
| 1279 | 
            -
            				String('foo and bar')
         | 
| 1280 | 
            -
            			end
         | 
| 1281 | 
            -
            		end
         | 
| 1365 | 
            +
                	def to_log arg
         | 
| 1366 | 
            +
                		(@log ||= Logger.new($stdout)).warn(arg)
         | 
| 1367 | 
            +
                	end
         | 
| 1368 | 
            +
                end
         | 
| 1282 1369 |  | 
| 1283 | 
            -
             | 
| 1284 | 
            -
             | 
| 1285 | 
            -
             | 
| 1370 | 
            +
                String() do
         | 
| 1371 | 
            +
                	inject Log()
         | 
| 1372 | 
            +
            	
         | 
| 1373 | 
            +
                	def show
         | 
| 1374 | 
            +
                		to_log self
         | 
| 1375 | 
            +
                	end
         | 
| 1376 | 
            +
                end
         | 
| 1377 | 
            +
                
         | 
| 1378 | 
            +
                str = String('don't leave a trace')
         | 
| 1379 | 
            +
                str.show                                      # doh!!
         | 
| 1380 | 
            +
                
         | 
| 1286 1381 |  | 
| 1287 | 
            -
             | 
| 1382 | 
            +
            For more on this see, the rspec files and the Jackbox blog at <a href="http://jackbox.us">http://jackbox.us</a>.  
         | 
| 1288 1383 |  | 
| 1289 | 
            -
            #### reclass? | 
| 1384 | 
            +
            #### #reclass?(klass)
         | 
| 1290 1385 |  | 
| 1291 | 
            -
            This helper verifies a certain  | 
| 1386 | 
            +
            This helper verifies a certain re-class exists within the current namespace.  It returns a boolean.  Ex:
         | 
| 1292 1387 |  | 
| 1293 1388 | 
             
                module One
         | 
| 1294 1389 | 
             
                  if reclass? String
         | 
| @@ -1298,7 +1393,7 @@ This helper verifies a certain class re-classing exists within the current names | |
| 1298 1393 |  | 
| 1299 1394 |  | 
| 1300 1395 | 
             
            ---
         | 
| 1301 | 
            -
            For more information and additional examples see the rspec examples on this project.  There you'll find a long list of  | 
| 1396 | 
            +
            For more information and additional examples see the rspec examples on this project.  There you'll find a long list of over __200__ rspec examples and code showcasing some additional features of Jackbox Injectors along with some additional descriptions.
         | 
| 1302 1397 |  | 
| 1303 1398 | 
             
            ---
         | 
| 1304 1399 | 
             
            ## Additional Tools
         | 
| @@ -1343,7 +1438,7 @@ With Prefs you can add persistent properties to a class.  These properties persi | |
| 1343 1438 | 
             
                Jester.reset :value
         | 
| 1344 1439 | 
             
                Jester.value.should == 10 
         | 
| 1345 1440 |  | 
| 1346 | 
            -
            There is also command line utility called **jackup** that simply allows users to bring  | 
| 1441 | 
            +
            There is also command line utility called **jackup** that simply allows users to bring projects up to a *"Jackbox level"*.  It inserts the right references and turns the targeted project into a bundler gem if it isn't already one also adding a couple of rake tasks.
         | 
| 1347 1442 |  | 
| 1348 1443 | 
             
            ## Availability
         | 
| 1349 1444 |  |