3
\$\begingroup\$

To begin, I have an XML file at /Users/gaze/lab/lab/gpib_lib/out.xml that contains lines like...

<MemberCall method_name="setFastCoupleMode" callee_name="GPIB_7280" fname="/Users/gaze/lab/lab/gpib_lib/../apps/capbridge/capbridge.C" lineno="394" colno="9" />

<MemberCall method_name="setInputLineFilter" callee_name="GPIB_7280" fname="/Users/gaze/lab/lab/gpib_lib/../apps/capbridge/capbridge.C" lineno="395" colno="9" />

<MemberCall method_name="setFrequency" callee_name="capacitanceBridge" fname="/Users/gaze/lab/lab/gpib_lib/../apps/capbridge/capbridge.C" lineno="526" colno="5" />

<MemberCall method_name="getFrequency" callee_name="capacitanceBridge" fname="/Users/gaze/lab/lab/gpib_lib/../apps/capbridge/capbridge.C" lineno="528" colno="10" />

<MemberCall method_name="setupBandpass" callee_name="Stream_SR560" fname="/Users/gaze/lab/lab/gpib_lib/../apps/capbridge/capbridge.C" lineno="531" colno="9" />

<MemberCall method_name="thr" callee_name="listOutputFilter" fname="/Users/gaze/lab/lab/gpib_lib/../apps/capbridge/capbridge.C" lineno="540" colno="5" />

<MemberCall method_name="setBias" callee_name="capacitanceBridge" fname="/Users/gaze/lab/lab/gpib_lib/../apps/capbridge/capbridge.C" lineno="546" colno="5" />

To process it into a list of unique class.method() invocations I use the following code. I filter out all calls that occur outside my codebase, which is located at fpath.

filename←'/Users/gaze/lab/lab/gpib_lib/out.xml'
fpath←'/Users/gaze/lab/lab'

getxml←{⎕XML ⊃⎕NGET ⍵}
doc←getxml filename
attrib←↑doc[;4]

colnames ← attrib[1;;1]
col ← {attrib[;(attrib[1;;1]⍳⊂⍵);2]}
oot ← ((⍴fpath)↑¨col'fname')∊⊂fpath

fn ← (1+⍴fpath)↓¨oot/(col'fname')
cn ← oot/(col'callee_name')
mn ← oot/(col'method_name')

allUsed ← ∪(⍉↑(cn mn))[⍋cn;]

OOT denotes "out of tree." I'm curious if you might have suggestions about how to structure this in a larger application. I'm mostly curious how one should set fpath, should it change from invocation to invocation of allUsed, if this code is factored such that you can change filename. I don't exactly want to make allUsed a dyad s.t. fpath is on the right and filename is on the left, since that seems a bit wrong, should there be a more general allUsed that should indeed be a dyad. Should fpath be a global variable which is changed throughout the execution of a larger program? What's the right structure here? If you have any little details you'd improve upon here, I'd love to know as well.

\$\endgroup\$
3
  • \$\begingroup\$ Oh, sorry I misread it as api. \$\endgroup\$ – πάντα ῥεῖ Apr 3 '20 at 14:33
  • \$\begingroup\$ The current question title, which states your concerns about the code, is too general to be useful here. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How to get the best value out of Code Review: Asking Questions for guidance on writing good question titles. \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Apr 3 '20 at 15:26
  • \$\begingroup\$ @SᴀᴍOnᴇᴌᴀ I've taken a stab at the title (and added tag). Better? \$\endgroup\$ – Adám Apr 5 '20 at 6:09
5
\$\begingroup\$

Regarding the primary question, your code is very close to being a well-defined function. Simply wrap the entire code in a function, making filename the right argument, fpath the left argument, and allUsed the result like so (with a couple of unreference lines omitted):

 GetAllUsed←{
         filename←⍵
         fpath←⍺
         getxml←{⎕XML⊃⎕NGET ⍵}
         doc←getxml filename
         attrib←↑doc[;4]
         col←{attrib[;(attrib[1;;1]⍳⊂⍵);2]}
         oot←((⍴fpath)↑¨col'fname')∊⊂fpath
         cn←oot/(col'callee_name')
         mn←oot/(col'method_name')
         ∪(⍉↑(cn mn))[⍋cn;]
     }

I cannot envision a scenario where one might not want it as a dyadic function, or where one would want to introduce a global variable of any sort. I prefer the file name as the right argument, leaving the opportunity to make the left argument optional (possibly having it default to the first few path segments of the right arg?)

Regarding the actual code, the biggest issue is that it relies on the set of attributes for each MemberCall element being exactly the same. An additional or missing attribute will cause the code to fail, with an index error most likely, or produce a bad result.

If it is indeed the case that the attribute sets are identical, then a much simpler approach can be taken by restructuring the attributes for all elements into a single matrix of name/value pairs. There is no need to construct a rank-3 array as is done currently.

If this is not the case, then one approach is to define a little getter function that picks out a given attribute for each element. This function can handle the issue of missing or extra attributes, attributes in any order, etc.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.