# Crystal tool expand example?

**URL:** <https://forum.crystal-lang.org/t/crystal-tool-expand-example/3946>\
**Category:** Help & Support\
**Created:** [October 15, 2021, 2:18am UTC](https://forum.crystal-lang.org/t/crystal-tool-expand-example/3946 "2021-10-15T02:18:33Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![rogerdpack](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rogerdpack/32/117_2.png) [@rogerdpack](https://forum.crystal-lang.org/u/rogerdpack)\
**Post date:** [October 15, 2021, 2:18am UTC](https://forum.crystal-lang.org/t/crystal-tool-expand-example/3946/1 "2021-10-15T02:18:33Z")

</div>

Could somebody help me find an example of “crystal tool expand” where it works? Mine always says “no expansion found” …

What I’m kind of wishing for is a way to see “a file after the macros are fully expanded”…

In case useful in cases like these:

> <https://github.com/crystal-lang/crystal/issues/2785#issuecomment-596778257>
>
> While porting some Ruby code to Crystal, I ran some specs and found that the err…or backtraces were missing huge chunks of code frames. It was very painful to debug the issues due to incomplete backtraces, often missing line numbers. Here's an example:
> 
> \`\`\`
> cast to Int failed
> \[4525793250\] \*CallStack::unwind:Array(Pointer(Void)) +82
> \[4525793153\] \*CallStack#initialize\<CallStack\>:Array(Pointer(Void)) +17
> \[4525793112\] \*CallStack::new:CallStack +40
> \[4526322281\] \*Exception@Exception#initialize\<TypeCastError, String\>:CallStack +41
> \[4526322205\] \*TypeCastError#initialize\<TypeCastError, String\>:CallStack +29
> \[4526322148\] \*TypeCastError::new\<String\>:TypeCastError +100
> \[4525582152\] ~proc(HTTP::Server::Context -\> String)@./src/sidekiq/web.cr:88 +2072
> \[4525566338\] ~proc(HTTP::Server::Context -\> String)@./libs/kemal/kemal/route.cr:10 +66
> \[4526712301\] \*Kemal::RouteHandler#process\_request\<Kemal::RouteHandler, HTTP::Server::Context\>:HTTP::Server::Context +125
> \[4526712157\] \*Kemal::RouteHandler#call\<Kemal::RouteHandler, HTTP::Server::Context\>:HTTP::Server::Context +93
> \[4525709936\] \*get\<String, Nil, Nil\>:(HTTP::Server::Response::Output | IO::FileDescriptor+ | Int32 | Nil) +192
> \[4526809829\] \*/Users/mike/src/sidekiq.cr/spec/web\_spec.cr#get\<String\>:(HTTP::Server::Response::Output | IO::FileDescriptor+ | Int32 | Nil) +21
> \[4525728014\] ~proc( -\> Void)@./spec/web\_spec.cr:286 +2718
> \[4525503099\] \*it\<String, String, Int32, &( -\> Void)\>:(Array(Spec::Result) | Bool | Nil) +427
> \[4525704007\] ~proc( -\> Void)@./spec/web\_spec.cr:4 +1831
> \[4525994230\] \*Spec::RootContext::describe\<String, String, Int32, &( -\> Void)\>:Spec::Context+ +310
> \[4525501977\] \*describe\<String, String, Int32, &( -\> Void)\>:Spec::Context+ +9
> \[4525431833\] \_\_crystal\_main +31705
> \[4525483016\] main +40
> \`\`\`
> 
> Note the top element in my code: sidekiq/web.cr:88:
> 
> \`\`\` ruby
> get "/busy" do |x|
> ecr("busy")
> end
> \`\`\`
> 
> Great. ECR pushes the entire template into the code. None of it is visible in backtrace. So I throw in some \`raise "boom"\` in the template to bisect down to this line:
> 
> \`\`\` ruby
> \<% x.processes.each do |process| %\>
> \`\`\`
> 
> This calls Sidekiq::ProcessSet#each:
> 
> \`\`\` ruby
> def each
> Sidekiq.redis do |conn|
> prcs = conn.smembers("processes")
> procs = \[\] of String
> prcs.each { |x| procs \<\< x.as(String) }
> procs.sort!
> 
> # We're making a tradeoff here between consuming more memory instead of
> # making more roundtrips to Redis, but if you have hundreds or thousands of workers,
> # you'll be happier this way
> results = conn.pipelined do |ppp|
> procs.each do |key|
> ppp.hmget(key, "info", "busy", "beat", "quiet")
> end
> end.as(Array(Redis::RedisValue))
> 
> results.each do |x|
> packet = x.as(Array(Redis::RedisValue))
> info = packet\[0\].as(String)
> busy = packet\[1\].as(Int).to\_i64 # \<========= ACTUAL BUG
> beat = packet\[2\].as(String).to\_f64
> quiet = packet\[3\]?.to\_s == "true"
> 
> hash = JSON.parse(info).as\_h
> hash\["busy"\] = busy
> hash\["beat"\] = beat
> hash\["quiet"\] = quiet
> yield Process.new(hash)
> end
> end
> 
> nil
> end
> \`\`\`
> 
> This is one example of how debugging is painful today due to huge gaps in error backtraces. The equivalent Ruby backtrace would have 4-6 frames between these two lines and make for a 20 second bugfix instead of a 20 minute bughunt.
> 
> \`\`\`
> \[4526322148\] \*TypeCastError::new\<String\>:TypeCastError +100
> \[4525582152\] ~proc(HTTP::Server::Context -\> String)@./src/sidekiq/web.cr:88 +2072
> \`\`\`
> 
> Are there any easy wins to improve the situation?

> [@Undefined local variable or method](https://forum.crystal-lang.org/t/undefined-local-variable-or-method/3934/10):
>
> If it would be helpful you could look into integrating [Validator - Athena](https://athenaframework.org/Validator). Follows a similar pattern of having classes to represent the constraints, but also supports multiple violations at once, among other features.

Thanks!

---

<div class="post-metadata">

**Author:** ![rogerdpack](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rogerdpack/32/117_2.png) [@rogerdpack](https://forum.crystal-lang.org/u/rogerdpack)\
**Post date:** [October 15, 2021, 2:36am UTC](https://forum.crystal-lang.org/t/crystal-tool-expand-example/3946/2 "2021-10-15T02:36:15Z")

</div>

OK found one [Is there a way to see what a Crystal macro expands to? - Stack Overflow](https://stackoverflow.com/a/69579376/32453)

Still hope to someday be able to get full backtraces and “fully expanded files” for debugging 🙂

Also contains a fix’ish workaround for the “upgrade to 1.x Error: undefined method ‘mapping’ for JSON:Module” failure message.
