solnic changed the topic of #rom-rb to: Ruby Object Mapper | Mailing List: https://groups.google.com/forum/?fromgroups#!forum/rom-rb | Logs: http://irclog.whitequark.org/rom-rb
<mbj> re Rspec.describe
<mbj> this is a step in the correct direction
<mbj> But it is STILL accumulating state inside the Rspec singleton.
<mbj> it should be an application specific constant
<mbj> So you could do "spec algebra" with multiple expectation objects.
<mbj> s/expectation/spec_root/
<mbj> I did not followed rspec development very close, I just consumed rspec as is.
<mbj> But I'll end up in doing my own framework. Maybe during summer vacation.
<mbj> It is a good project to keep brain busy :D
<dkubb> I would be fine if I could get describe after doing include SomeModule at the top
<dkubb> automatically monkey patching is the thing that's actually bad
<mbj> jo
<dkubb> but yeah, I suspect there are tons of methods and constants in the RSpec namespace
<dkubb> accumulating that complexity in a single namespace, in the name of a better interface, is still a mistake imho
<mbj> So an application specific root would be better
<mbj> MyAppsSpecs.describe
<mbj> or include MyappsSpecs
<mbj> describe
<mbj> going to sleep
<mbj> meet you tomorrow
<dkubb> I just wish I could say something like: describe MyNamespace, '#read' .. and then describe MySubclass, '#read' do; inherits MyNamespace, '#read'
<dkubb> and then I could have my own before and let blocks that I can override
<dkubb> this would allow me to test LSP
<dkubb> there was a neat article about that and minitest: http://wojtekmach.pl/blog/2012/07/17/liskov-principle-and-minitest/
mbj has quit [Ping timeout: 276 seconds]
machuga is now known as machuga|away
mbj has joined #rom-rb
snusnu has joined #rom-rb
<mbj> snusnu: hola!
<mbj> snusnu: Thougt you are on a longer vacation and coming back in 2 days.
<mbj> dkubb: hola, sorry for dropping out so fast yersterday.
<mbj> dkubb: I have an interesting thought. We Adamantium{,::FLat} that makes objects immutable. But sometimes I need an object that is mutable. (Root of the object tree) This object sometimes gets passed into a freezer. So IMHO we need Adamantium::Mutable that noops #freeze and #frozen => true
<mbj> dkubb: So I can greatly reduce memoize :freezer => :noop usage!
machuga|away is now known as machuga
<Gibheer> mbj: so it should lie about its state?
<mbj> Gibheer: yeah
<Gibheer> and what would you gain from lying? You would not like an API which is lying to you, right?
<Gibheer> it will just cause pain :/
<mbj> Gibheer: It wount, but use it wisely
<mbj> Gibheer: I already use this for 1 in 1000 classes :D
<Gibheer> why not just return false for frozen?
<mbj> Gibheer: Because ice_nine will try to freeze it.
<mbj> Gibheer: All time it sees that object :D
<Gibheer> if it is intended like this, then it would be the correct way
<Gibheer> or you create a flag which represents the purpose, like mutable?
<mbj> Gibheer: I cannot argue deeply now, busy. later.
<mbj> But I think it is correct, sometimes.
<Gibheer> mbj: I see why you would need it, but lying about an objects features feels wrong to me.
<mbj> Gibheer: #freeze, #frozen? is a protocoal
<mbj> s/protocal/protocol/
<mbj> I need a special protocol entity
<mbj> For edge cases.
<mbj> And we support these edge cases with :freezer => :noop already.
<mbj> But all users need to know "dont freeze this object".
<mbj> With Adamantium::Mutable you can remove all these special memoizers.
<mbj> So I replace lots of crap with less crap. Okay for me :D
<mbj> s/crap/imperfectness/
<dkubb> mbj: I'm fine with this as a stop-gap, but we need a way to configure ice_nine without making special freezers. some kind of dsl that can do it quickly and easily
<mbj> dkubb: yeah
<mbj> Pls comment on spelling/grammar errors of the new Mutation (operands) section in the mutant readme. https://github.com/mbj/mutant/blob/master/README.md#mutations
<mbj> dkubb: Released as v0.0.11
<dkubb> mbj: oh cool. did you drop a non-beta mutant release?
<dkubb> mbj: I would probably write "majority of ruby's" instead of "majority of rubies"
<dkubb> actually lemme comment in the commit
<dkubb> *on
<mbj> dkubb: I'm very close to push the world preloading
<mbj> dkubb: This will land in 0.3
<mbj> dkubb: I plan to do a non beta release of mutant at 1. Aug, when whitequark releases a stable parser lib.
<mbj> dkubb: Early measurements show a significant mutant speedup!
<dkubb> nice!
<dkubb> mbj: I'm going to try to set aside time each week to add a dedicated mutator class for each of those generic nodes
<dkubb> I'll do one per week at least
<mbj> dkubb: Nice!
<dkubb> I think some of them will be really easy
<mbj> jo
<dkubb> I'll try to create a kind of mutation template file to use to start new ones
<dkubb> something basically equivalent to the Generic mutator
<mbj> Adding mutators is so easy. Dunno if we need a template.
<mbj> class YourMutator < Mutant::Mutator::Node
<mbj> handle :your_type
<mbj> def dispatch
<mbj> ... do stuff here
<mbj> end
<mbj> end
<mbj> And make dispatch private.
<mbj> You can access node (the input)
<mbj> And use various helpers.
<dkubb> ahh ok
<dkubb> hmm, I wish we had stats on how often a generic node is seen in given source
<dkubb> that would be an awesome way to know where to spend our time adding new mutators
<dkubb> maybe a feature to add in the future?
<dkubb> if I knew that and "and" node is seen 50 times, and the next largest node is 10, then I could add an "and" node mutator fairly quicklly
<dkubb> I think maybe it would be possible to have a base class for the and/or connectives
<mbj> dkubb: It would be easy to add.
<mbj> 2 changes needed:
<mbj> mom, lemme think longer.
<dkubb> it would be nice to have a way to report that after the mutation stats
<mbj> dkubb: I think it would be most easy to add this to reporting.
<mbj> Once the reporter runs it has access to the AST of all mutations.
<mbj> So we could walk that mutated asts and count the nodes still handled via generic mutator.
<mbj> (Getting that list is easy, walk and aggregate the registry)
<mbj> *mutator registry
<dkubb> interesting
<mbj> Plug it here
<mbj> object.subjects.each { |subject| subject.mutations.each { |mutation| aggregate(mutation.node) } }
<mbj> mutation.node is an instance of Parser::AST::Node
<mbj> You'd need to walk this and scan for nodes that are handled by generic mutator.
<mbj> BTW I'm stupid.
<mbj> DONT scan the mutations.
<mbj> Scan the subjects node, sorry.
<mbj> object.subjects.each { |subject| aggreate(subject.node) }
<mbj> And you'd not have to do any magic with the registry
<mbj> Mutator::Registry.lookup(node) => Class:Mutant::Mutator::Node
<mbj> So just do Mutator::Registry.lookup(node) == Mutator::Node::Generic
<mbj> And you are done.
<mbj> Mhh, I should do this *now* :D
<mbj> mom
<dkubb> cool
<dkubb> hehe
<dkubb> I'd guess there's, what, 15-20 nodes? we could display the top 5 or something and then people who want to contribute could just pop one of those off and work on it in a PR
<dkubb> what I would probably do is keep a list of 100% mutation covered gems, and tell people to run mutant with them and add a node for the #1 entry
<dkubb> then maybe they'll knock it down from 100%.. gamify it
<dkubb> if anyone knocked down one of my 100% covered gems in mutation coverage I would immediately fix it
<mbj> dkubb: done
<mbj> (waiting for local rake ci)
<mbj> dkubb: This is so nice. I love this design.
<mbj> nesting is:
<mbj> Reporter(Runner(DomainObject))
<mbj> So reporter can access runner (with details the runner accumulates)
<mbj> And reporter can peek into DomainObject
<mbj> Mutant::Subject in this case.
<dkubb> oh nice!
<dkubb> I'll use this report to priorities my time
<dkubb> I'll start with the top nodes in axiom-types and then branch out
<dkubb> I still have to get axiom to 100% coverage too
<dkubb> maybe after I get mutable materialized relations
<mbj> I like the code
<mbj> "Walker" needs to be moved away, I need him in another case also.
<mbj> release?
<mbj> yeah
<dkubb> sure
<dkubb> when in doubt, release
<dkubb> mbj: did you know about the named sprintf options?
<mbj> dkubb: yes
dkubb has quit [*.net *.split]
xargoon has quit [*.net *.split]
ChanServ has quit [*.net *.split]
shingara has quit [*.net *.split]
kalleth has quit [*.net *.split]
mbj has quit [*.net *.split]
postmodern has quit [*.net *.split]
cox has quit [*.net *.split]
indrek has quit [*.net *.split]
snusnu has quit [*.net *.split]
stormwin1 has quit [*.net *.split]
xybre has quit [*.net *.split]
kpwz has quit [*.net *.split]
Gibheer has quit [*.net *.split]
dbussink has quit [*.net *.split]
elskwid has quit [*.net *.split]
namelessjon has quit [*.net *.split]
machuga has quit [*.net *.split]
pdswan has quit [*.net *.split]
_whitelogger__ has joined #rom-rb
machuga is now known as machuga|away
<dkubb> no, not really
<dkubb> I usually run them locally
<mbj> Okay, running mutant on axiom locally
<mbj> back in 45 - 60min to post results (moving home and back to office)
xargoon has quit [*.net *.split]
xargoon has joined #rom-rb
<dkubb> heh
elskwid_ has joined #rom-rb
elskwid has quit [*.net *.split]
namelessjon has quit [*.net *.split]
elskwid_ is now known as elskwid
<dkubb> mbj: this is what I get from axiom-types: https://gist.github.com/dkubb/868f4c6d303e4d246bb8
<mbj> lol
<dkubb> hehe
<mbj> same second :D
<dkubb> lvar is going to be my first
<dkubb> is that assignment to a local variable?
<mbj> no this is read of locatl variable
<dkubb> ahh ok
<mbj> This lists all nodes.
<dkubb> cool
<dkubb> I'll start with these lists, probably the axiom-types one first since it's 100% covered
<dkubb> and I can iterate between adding a mutator and fixing it
<mbj> Yeah
<mbj> What mutations you plan?
<dkubb> I'll start with lvar first
<mbj> yeah
<dkubb> oh I see
<dkubb> I dunno actually
<mbj> hehe
<mbj> This is the hard question
<dkubb> I guess it might require some experimentation
<mbj> I think lvar should be mutated to nil
<mbj> at least
<dkubb> I need to add a mutation locally, then see if I can actually fix it
<dkubb> yeah, I was thinking that
<dkubb> does the generic nodes have any mutations?
<mbj> no
<mbj> generic mutator only dispatches to child
<mbj> lvar does not have a child so it is basically a noop
<dkubb> ahh I see
<mbj> Introduced generic to make sure no mutatable nodes within a prev nooped node would be missed
<dkubb> what about mutating it to be some kind of object that blows up on usage
<mbj> Yeah
<mbj> If you need to construct "new ruby"
<dkubb> I could inherit from BasicObject and then add a missing_method method that explodes
<mbj> Just use the s() helper.
<mbj> for example an lvar would be this: s(:foo) # lvar "foo"
<mbj> a call looks like this: s(:send, nil, :bar) # send to implicit self "bar"
<dkubb> Class.new(BasicObject)
<dkubb> Class.new(BasicObject) { def method_missing(*) raise end }
<dkubb> or something
<mbj> s(:send, s(:const, nil, :Class), :new, s(:const, nil, :BasicObject)))
<mbj> you need to emit the result of this.
<mbj> You can always use parser -e "your code" to see sexps.
<mbj> dkubb: I'd personally reduce code that we put inside mutations
<mbj> so instead of an lvar I'd emit: "Mutant::DONT_TOUCH_ME"
<mbj> And DONT_TOUCH_ME would be an instance of the class you showed.
<dkubb> I think that Class.new(BasicObject).new would be enough
<dkubb> it wouldn't respond to anything
<dkubb> hehe
<mbj> I think this mutation would not be killable.
<dkubb> yeah I would probably make a Mutant constant
<dkubb> you don't think so?
<mbj> What about a method like this:
<mbj> def foo(bar)
<mbj> if bar
<mbj> baz(bar)
<mbj> eend
<dkubb> at some point I wonder if we should have a way of tagging mutations as experimental, and they only are run when the --experimental flag is provided
<mbj> Yeah
<mbj> This method will never call a method on bar
namelessjon has joined #rom-rb
<dkubb> if no one reports any bugs on it for a while then we promote it
<dkubb> hmm
<dkubb> yeah, I guess it's in boolean context
<mbj> Yeah, but that DONT_TOUCH_ME will not be the receiver of any method call.
<dkubb> I wonder about those cases where the lvar can be nil
<mbj> So that replacement will not trigger any behavior
<mbj> nil is falsy
<mbj> and branch is not taken all the times
<dkubb> no, I don't mean in this case
<mbj> specs should measure this.
<dkubb> I just meant in the general case
<dkubb> of replacing it with nil
<mbj> If you have an lvar there should be a case where it is not nil!
<mbj> So this mutation is valid, IMHO.
<dkubb> yeah
<dkubb> I guess if it always expects nil, then wth are you doing
<dkubb> just don't pass in anything then
<mbj> I think lvar, gvar and ivar can be handled with the same mutator.
<dkubb> ahh interesting
<mbj> just call handle multiple times or with multiple arguments
<mbj> handle(:lvar, :ivar, :gvar)
<mbj> later we could expand ivar and gvar to snoop for other ivars or gvars and use another one.
<dkubb> ahh cool
<dkubb> so once I get it working for one I can test the others easily
<mbj> via "mutation runtime reflection" - I'm a buzzword generator :D
<dkubb> heh
<mbj> hey, I invented "dynamic in-memory vendoring" also (Zombie) :D
<dkubb> I think it would be nice to have a stand-alone gem that does that
<mbj> Yeah
<dkubb> it's like sandboxing kinda
<mbj> called zombifier
<mbj> Mine is not perfect currently
<mbj> if you do:
<mbj> require 'foo'
<mbj> class Bar
<mbj> end
<mbj> require 'baz'
<dkubb> yeah, it doesn't have to be current to be a gem
<mbj> it will vendor the contents of foo followed by bar and than Bar
<mbj> I but it should do: 'foo', Bar, 'baz'
<mbj> where it does (correciton) 'foo', 'baz', Bar
<mbj> This does not cause any failure, currently.
<mbj> But that zombifier is nothing more than a limited AST based ruby interpreter.
<mbj> I could also expand it to hook Kernel.require
<mbj> dkubb: Keep in mind we have statement deletion
<mbj> So if you target zsuper you might think: "I could remove the super call altogether"
<mbj> But this will already be done by parent mutator
<mbj> dkubb: I thought longer about this, lvar => nil seems to be the only valid mutation
<mbj> Other possiblities are not structural and should be done later.
<mbj> Same for ivar, and gvar.
<dkubb> yeah, I think the main thing is to get explicit mutators in place. we can continue to add stuff over time
<dkubb> but it would be nice to be doing *something* to those nodes
<dkubb> even the most basic mutation
<mbj> dkubb: Yeah
<dkubb> more mutations will come with familiarity
<mbj> dkubb: You want add this for yourself?
zekefast has joined #rom-rb
<dkubb> the lvar mutator?
<dkubb> yeah I was going to add it today. it'll give me a chance to get familiar with adding new mutators
<dkubb> then I can be more help later on with more complex stuff
<mbj> dkubb: Yeah
<mbj> dkubb: It is 4 loc
<dkubb> if two of us can dig around and add stuff that's better
<dkubb> heh
<mbj> def dispatch; emit_nil; end
<dkubb> once we get the basic ones in then we can start brainstorming about more mutators and/or stealing from other mutation test frameworks
<dkubb> I see this as getting the low hanging fruit
<mbj> dkubb: My research shows mutant has many many many more mutations than other test frameworks.
<dkubb> yeah
<dkubb> but there may be a few they've identified that we can steal
<mbj> The only ones mutant is missing are boolean and relational operator expressions mutation
<dkubb> it won't take much time to confirm
<mbj> == to =>
<mbj> != to ==
<mbj> etc.
<dkubb> I would love to do that expansion one
machuga|away is now known as machuga
<mbj> expansion?
<dkubb> a >= b to a > b || a == b .. then mutating each of those
<mbj> dkubb: I think this will have unkillable operators.
<mbj> ohh, I see
<dkubb> or I guess you could get that from simply doing a >= b to a > b and a == b
<mbj> thought you where talking about op assign!
<dkubb> nope
<dkubb> I don't even think expansion is needed
<mbj> yeah, the one you showed makes sense
<dkubb> in order to test >= out you do need to handle both cases
<dkubb> both > and ==
<mbj> BTW you dont need to expand and reenter mutator
<mbj> detecting >= and friends is easy
<mbj> Just add detect this case and run a Send::Binary::GTE mutator.
<dkubb> in the past I've actually manually expanded those statements, then mutation covered them, then compacted them
<mbj> I so this for the various send edge cases already:
<mbj> dkubb: This is how I detect index, and binary operator edge cases in the send mutator: https://github.com/mbj/mutant/blob/master/lib/mutant/mutator/node/send.rb#L58-L81
<dkubb> I'd like to do that send => public_send one too
<mbj> And it *should* have specific branches for >= etc.
<dkubb> do you need to handle splat like that anymore?
<dkubb> I thought you added a splat handler
<mbj> dkubb: Because splat cannot be standalone.
<mbj> *foo
<mbj> is not valid ruby
<mbj> that binary mutator does this
<mbj> a op b => a, b
<mbj> but if b is a splat it cannot stand alone.
<mbj> Sure there is a splat specific mutator (that removes the splat)
<mbj> But we cannot emit that splat as valid code.
<dkubb> ahh ok
<mbj> Lets say it this way: Not each leave of the AST is a valid input. Some nodes require a context to be valid.
<mbj> So splat is only valid in the context of an masgn (mutliple assignment) or method call.
<dkubb> I guess it'll all make more sense once I start working directly with it
<dkubb> I've only worked with other parts of mutant
<mbj> This one is clearly the most interesting one.
<mbj> I hope you see how much I invested in making the mutators really "clean".
<dkubb> hehe
<dkubb> I'm sure I will
<mbj> All that helpers in the baseclass should add a smile on your face.
<mbj> Helper is the wrong word.
<mbj> They depend on instance state :D
mbj has quit [Quit: leaving]
mbj has joined #rom-rb
mbj has quit [Quit: leaving]
mbj has joined #rom-rb
zekefast has quit [Quit: Leaving.]