12 Mar 2014, 20:10
Photo_17_pragsmall

Paolo Perrotta (49 posts)

A few hours after the public announcement, the book is already flying off the (virtual) shelves. I’m a happy author. Thank you, pragmatic readers!

What’s new in the second edition:

  • Updated to the new features in Ruby 2.x, such as prepend and Refinements.
  • Rails has changed a lot. The Rails chapters in part 2 are almost a complete rewrite.
  • Most examples from real-life gems were showing their age. I replaced them with fresher examples from gems that are popular today.
  • Some readers loved the “story” involving Bill and the office. Some other readers hated it. In this edition, Bill is still there, but he pops up when the story calls for him instead of lurking on each and every page.
  • My ideas about how much metaprogramming is good/appropriate have changed in some cases. The new edition reflects that.
  • Finally, we reviewed the entire text, cover to cover, smoothing out dozens of small wrinkles.

Enjoy!

13 Mar 2014, 14:05
Generic-user-small

xinke li (2 posts)

Thank you for releasing the book

14 Mar 2014, 05:22
Hacker_pragsmall

Arda Karaduman (1 post)

Thank you for the book ! also, will there be a discount for first edition owners ?

15 Mar 2014, 11:10
Photo_17_pragsmall

Paolo Perrotta (49 posts)

xinke, Arda, you’re welcome!

Arda: yes, I see that the Prags are giving a discount coupon to owners of the first edition. Register your copy of the first edition with the Prags (if you didn’t buy from this site) and check your account. You should see your coupon there. At least, that’s what happened to me. ;)

31 Mar 2014, 23:49
Generic-user-small

Ernest Szulikowski (2 posts)

Hi,

Paolo, what is your estimate percentage of completion of B 1.0 release, comparing to planned final release.

Thanks.

10 Apr 2014, 09:54
Generic-user-small

Guru M (1 post)

Hi,

1) Really loved the first edition of your book. Found the Mentor discussion to be quite involving and not at all irritating. Wish more books were written like this.

2) A diagram is worth a thousand words (literally). For the visual-learner esp. it’s easy to remember a diagram than a few hundred words of text. For the more textual oriented you can include text form of the explanation as well.

Really liked the diagram of method lookup ‘right and up’ in Dave Thomas’s video on metaprogramming.

Regards, Guru M.

11 Apr 2014, 03:39
Photo_17_pragsmall

Paolo Perrotta (49 posts)

Ernest: It’s hard to talk about %, but as of beta 2.0, there are only two short chapters left, and a handful of small fixes. The missing chapters will be about 10 pages each, and they’re the very last regular chapters in the entire book - so you could say that the book is already readable, but it’s missing the last 20 pages.

Guru M: Thanks - I also like the Bill story. It was probably a bit overplayed, so I made it less intrusive in this 2nd edition. All of the story is still there, but it’s not nearly as distracting as in the first edition. About the diagrams: the book has a few diagrams already, including “right then up”. Do you think they’re not enough?

09 May 2014, 13:35
Kl_pragsmall

Kalle Lindström (4 posts)

Hi Paolo, I’m really enjoying the book so far, great stuff! I was just reading through the DSL chapter and thought of a third way to run RedFlag that doesn’t pollute the global scope or add any kernel methods:

module RedFlag
  class << self

    def setup(&block)
      @setups << block
    end

    def event(description, &block)
      @events << {:description => description, :condition => block}
    end
  end

  @setups = []
  @events = []
  instance_eval(File.read('events.rb'))

  @events.each do |event|
    env = Object.new
    @setups.each { |setup| env.instance_eval &setup }
    puts "ALERT: #{event[:description]}" if env.instance_eval(&event[:condition])
  end
end
10 May 2014, 12:01
Photo_17_pragsmall

Paolo Perrotta (49 posts)

Hey, Kalle! I agree with you—your approach of wrapping everything in a module is the cleanest solution I can think of. Modules are good, and they make for great clean rooms.

Indeed, the only reason why I don’t use this approach in the book is that it doesn’t fit the order of arguments in the chapters: the book introduces singleton classes and the “class « self” syntax in the following chapter, so I’d have to make a potentially confusing forward reference. This was a problem that I struggled with a lot in the first edition: it’s very hard to introduce these concepts one at a time without overwhelming the reader. A bit shameful, I know, but I had to cope with this in the interest of readability. :
11 May 2014, 09:44
Generic-user-small

Vincent Zhu (2 posts)

Hey, Paolo

is there any way to get the A from C ?

module A
  def shoot
  end
end

class C
  class<< C
    include A
  end
  puts C.singleton_class.ancestors
  puts C.singleton_class.superclass
end

seems , the C.singleton_class.superclass should be A, but it isn’t. it’s “#<Class:Object>”

Also, in the B2.0 , when you talked about fall of alias_method_chain, we use redefine and super to tackle this, I think the include order must be important, the save must be included before we call super to invoke it, right?

thanks

11 May 2014, 11:03
Photo_17_pragsmall

Paolo Perrotta (49 posts)

Vincent, superclass() always returns the superclass, not the first ancestor. It just ignores modules. This is not unique to singleton classes - it’s the same with any class:

module M; end #=> nil

class C
 include M
end

C.superclass #=> Object
C.ancestors  #=> [C, M, Object, Kernel, BasicObject]

The superclass of C’s singleton class is Object’s singleton class. This twisted structure is described in the Class Definitions chapter.

when you talked about fall of alias_method_chain, we use redefine and super to tackle this, I think the include order must be important, the save must be included before we call super to invoke it, right?

I’m not sure I understood your question. Maybe you mean that you must build the ancestors chain before you call the method, or else super won’t work. If that’s what you mean, then yes, that is correct. If I misunderstood you, maybe send a code snippet my way as an example.

11 May 2014, 13:01
Generic-user-small

Vincent Zhu (2 posts)

Thanks. for the second question:

that’s exact what I meant.

for the first question:

So, is there any way we can get A from C in ruby even if A is one module?

12 May 2014, 12:06
Photo_17_pragsmall

Paolo Perrotta (49 posts)

So, is there any way we can get A from C in ruby even if A is one module?

The thing is, a class can include any number of modules. Usually, if you care about ancestors, then you want all of them, not just the first one. If for any reason you just want the first ancestor, be it class or module, then that’s simply:

C.ancestors[1]

(Because C.ancestors[0] is C itself).

If you want the first ancestor that is an included module (not a class), then I guess you can do something like:

C.ancestors.find {|a| a.class != Class }

Remember that including modules is the main mechanism to build a chain of ancestors. Inheritance also plays a role, but modules are arguably more important - and there is no limit to how many modules you can include in the same class.

Also remember that modules get into the ancestors chain in reversed order of inclusion:

module M1; end
module M2; end

class C
  include M1
  include M2
end

C.ancestors #=> [C, M2, M1, ...]
18 May 2014, 19:22
Generic-user-small

Micheal Winger (1 post)

Hello Paolo,

Loving the first edition of Metaprogramming Ruby. One concern I have is with the Quiz: A Better DSL, and I would like to find out if the following problem has been changed, or corrected, in the second edition: (I apologize if this is the wrong place to put this)

The first example you provided as a solution to the redflag.rb DSL is this:

def event(name, &block)
    @events[name] = block
end

def setup(&block)
    @setups << block
end

Dir.glob('*events.rb').each do |file| 
    @events = {}
    @setups = []
    load file
    @events.each do |name, event|
        env = Object.new
        @setups.each do |setup|
            env.instance_eval &setup
        end
        puts "ALERT: #{name}" if env.instance_eval &event
    end
end

This is fine, and works as expected with multiple *events.rb files. Then you went on (with the prompts of Bill’s voice of eliminating the ‘global’ instance variables) to show a better way to keep things clean:

lambda {
    setups = []
    events = {}

    Kernel.send :define_method, :event do |name, &block|
        events[name] = block
    end

    Kernel.send :define_method, :setup do |&block|
        setups << block
    end

    Kernel.send :define_method, :each_event do |&block|
        events.each_pair do |name, event|
            block.call name, event
        end
    end

    Kernel.send :define_method, :each_setup do |&block|
        setups.each do |setup|
            block.call setup
        end
    end
}.call

Dir.glob('*events.rb').each do |file|
    load file
    each_event do |name, event|
        env = Object.new
        each_setup do |setup|
            env.instance_eval &setup
        end
        puts "ALERT: #{name}" if env.instance_eval &event
    end
end

The big problem here is that when more than one *events.rb file gets loaded, these two sections of code behave quite different from each other. The first, for every file that got loaded, it created a clean slate of events and setups. This way, only the setups appropriate to that file got called, and the events from that file only ran once. However in the second version there is no reset for those setups and events - so events end up running repeatedly as well.

I’m learning this quite new to Ruby, so this is my attempt at fixing the issue here:

Add another define_method into the lambda:

Kernel.send :define_method, :clean_slate do
    setups = []
    events = {}
end

Then on the first line inside the Dir.glob().each:

clean_slate

Creates a new Array and Hash for each file so as not to have a large amount of setups in with each file.

Again, thanks so much for taking the time to make these books. If I purchase the 2nd edition while it’s in Beta, will I be able to get access to the main “non-beta” version without an extra purchase? I’ll be picking up this book once it’s out of Beta if not.

Mike

20 May 2014, 18:51
Photo_17_pragsmall

Paolo Perrotta (49 posts)

Hey, Micheal. You’re right - that was an inconsistency in the first edition. I seem to remember that one reader reported it as an errata.

In the second edition of the book, I avoided the problem altogether: I just changed the examples to only load a single file of events (events.rb). I did that because I didn’t think that I was adding anything to the chapter’s reason of being (explaining blocks) by fixing this particular inconsistency. It was just easier to remove it altogether.

So, I chickened out of the problem. ;) That being said, your clean_slate method looks perfect if you want to fix the inconsistency and still load multiple event files.

20 May 2014, 18:52
Photo_17_pragsmall

Paolo Perrotta (49 posts)

Oh, and Micheal… Yes, if you buy the beta, then you’ll get the final version of the book (and any future 2nd edition updates) once it’s out of beta. Thank you!

  You must be logged in to comment