These are chat archives for opal/opal

18th
Apr 2016
Mitch VanDuyn
@catmando
Apr 18 2016 17:22
Can I feed ruby AST to the opal compiler?
In otherwords I want to do something like this:
Opal::CompileAST(Parser::CurrentRuby.parse(some_block.source))
so it will compile existing server code to opal.
I am doing this now by just passing some_block.source directly to Opal, but I now want to do some tweaks to the AST before passing to opal, and rather than translate the AST back to source, then back to ruby I thought i would save a step.
possible?
Ilya Bylich
@iliabylich
Apr 18 2016 17:54
Opal compiler has a method process that takes s expression. You can get this sexp from Parser#parse
Just don't forget to wrap sexp to s(:top, parsed_sexp)
(this is what Opal compiler does internally)
May I ask you why do you need it? Usually we call Kernel#eval for dynamic source code. If your code is static, just require a compiled version. If you code is dynamic - then its AST is also dynamic and you can't partially pre-compile it. Most probably I'm missing something :smile:
Brady Wied
@wied03
Apr 18 2016 19:31
@catmando - I'm wondering the same thing. It also might break fairly easily since the compiler nodes are not necessarily an interface that people avoid changing
Mitch VanDuyn
@catmando
Apr 18 2016 20:26
@wied03 its for my server side test driver. So I can say:
it "will run this test in opal", :opal => true do
   expect(true).to be_truthy
end
and the expectation will run in opal-rspec
This message was deleted
This message was deleted
Elia Schito
@elia
Apr 18 2016 20:31
@rubys came up (years ago?) with a nice trick to compile to opal using the method_source gem, this looks like a very nice application for it
Mitch VanDuyn
@catmando
Apr 18 2016 20:32
it "does some fun isomorphic stuff", :js => true do 
  mount_component "Price", job: my_job = FactoryGirl.create(:job, :valid_job) do
    class Price < React::Component::Base 
      ... modify internal behavior of price for testing
    end
  end
  find(".the-price").text.should eq(my_job.price)
end
Brady Wied
@wied03
Apr 18 2016 20:34
@catmando - Don't you really just want to use mocks then (e.g. RSpec mocks) ?
Mitch VanDuyn
@catmando
Apr 18 2016 20:34
@wied03 - I could but we already have the factories set up.
Brady Wied
@wied03
Apr 18 2016 20:35
your example seems to indicate you want to modify the React component (not the factory)
Mitch VanDuyn
@catmando
Apr 18 2016 20:35
kind of a dumb example
here is a real one (I think I have given before)
Brady Wied
@wied03
Apr 18 2016 20:36
i do RSpec tests all the time that I run on both sides and I just surround some of my describe calls, etc. with RUBY_ENGINE guards
Mitch VanDuyn
@catmando
Apr 18 2016 20:37
require 'spec_helper'

describe 'chat component', :js => true, group: 2 do

  before(:each) do
    @agents_online = 0
    stub_request(:get, "support.catprint.com/customer/agent_online_check").
    to_return { {body: "{\"online_agents\":#{@agents_online},\"routing_agents\":#{@agents_online}}"} }
    FactoryGirl.create :production_center, domain: "127.0.0.1", code: "US"
  end

  it "switches from offline to online" do

    mount("Chat", online_text: "ONLINE", offline_text: "OFFLINE") do
      class Components::Chat < React::Component::Base
        POLL_INTERVAL = 1 # override default of 5 minutes
      end
    end

    page.should have_content('OFFLINE')
    wait_for_ajax
    @agents_online = 2
    Rails.cache.delete('desk_agents_online')
    page.should have_content('ONLINE')

  end
Brady Wied
@wied03
Apr 18 2016 20:39
@catmando - Much easier to do with unit tests in JS. beating a dead horse? ;)
Anyways, why not do what they said earlier and use eval ?
Mitch VanDuyn
@catmando
Apr 18 2016 20:40
@wied03 - I would very much like to see how this could be done easier than the above...
Brady Wied
@wied03
Apr 18 2016 20:40
what about eval ?
If you humor my unit test stuff though, that's much easier. You just monkey patch or mock that poll interval and you're done
because your tests are ruby/opal code running alongside the react component
Mitch VanDuyn
@catmando
Apr 18 2016 20:41
not quite - that component needs the production_center to work
Brady Wied
@wied03
Apr 18 2016 20:42
you could use factory girl on the opal side to avoid re-doing the work of constructing a production_center
or some support code that builds one manually
Mitch VanDuyn
@catmando
Apr 18 2016 20:43
@wied03 - and so we come full circle. You might remember our first conversation was about getting factory-girl opal to work with active-record
Elia Schito
@elia
Apr 18 2016 20:43
@catmando I think method_source is a viable option to collect the block source code, compile and run it with opal
Brady Wied
@wied03
Apr 18 2016 20:44
@catmando - Sounds like what @elia is mentioning + eval could help. seems like a lot of work just to test this though
Mitch VanDuyn
@catmando
Apr 18 2016 20:46

RE: eval... that is essentially what I am doing now... however the problem is if you have code like this:

 mount_component "Foo" do
    puts "hello"
end

the block.source for the do, includes the line "mount_component"
which we don't want
so I just use the AST tree to get the actual block

Brady Wied
@wied03
Apr 18 2016 20:46
what if you did def mount_component; yield; end somewhere else that wasn't dynamic
inject it (compiled via opal) in some place before the other stuff runs
or more like instance_eval(&block) but you get the idea
then you'd avoid coupling to compiler nodes
@catmando - as to AR. I have no problem with a PR for opal-factory-girl to work with the AR stuff as long as it doesn't require a bunch of additional stuff in there.
Mitch VanDuyn
@catmando
Apr 18 2016 20:49
@wied03 - at any rate this is all working today (and has been for sometime) I was just thinking it might be nice to git rid of the extra step. Right now it works like this block.source -> generate AST -> convert 3rd child back to source -> send to Opal to compile.
I was just thinking I could block.source -> generate AST -> send 3rd child directly to Opal::CompileAST
one less dependency, but as pointed out it depends on the two AST's being compatible.
@wied03 -> yeah so I looked at adding AR / reactive-record to opal-factory-girl, and decided it would be both easier and more powerful to simply be able to drive the unit tests directly from the server passing the already built models to the components.
the whole mount_component and associated code is less than 200 lines of code. I doubt I could get opal-factory-girl to work with active-record in any where near that (perhaps not.) But in addition it simplifies so much.
Brady Wied
@wied03
Apr 18 2016 20:59
another option is to make the timeout a prop that you can pass down from the server more easily
i tend to use that instead of constants anyways because it's easier to test from a unit testing standpoint
but it could help this as well
Mitch VanDuyn
@catmando
Apr 18 2016 21:01
@iliabylich - thanks for the answer BTW... I don't know if you followed all the chatter but I am as you suggest using Opal to just statically compile stuff. I just happen to know that the string I am giving to opal, came from an AST, so rather than turn it back into source, then reparse it, I thought it might be nice to send the AST directly to opal (which I will try fun grins anyway.)
@wied03 - a couple of reasons why this want to be a constant.
There is an underlying polling loop that updates the UI when chat is availability changes state. Each component is just reflecting the state of that store, and so there is only one polling interval.
If the chat component was not so small anyway, you could seperate the polling into its own store, and then the mount_component would be just providing an alternative store.
Elia Schito
@elia
Apr 18 2016 21:57
@/all releasing beta3, probably the last beta before a release candidate and a final release
Brady Wied
@wied03
Apr 18 2016 22:35
@elia - :+1: - opal-rspec passes fine with beta 3
Elia Schito
@elia
Apr 18 2016 22:58
@wied03 w00t! :D
CJ Lazell
@cj
Apr 18 2016 23:33
@elia shouldn't Opal.append_path return true?