kputnam / stupidedi

Ruby API for parsing and generating ASC X12 EDI transactions
BSD 3-Clause "New" or "Revised" License
265 stars 137 forks source link

Transaction splitting using notes/split.rb script: out of date? #232

Closed rmlrmlrmlrml closed 3 years ago

rmlrmlrmlrml commented 3 years ago

My team would benefit immensely from being able to take multi-transaction edi files and splitting them up into individual files as notes/split.rb illustrates. However, when I copy in the file and run I get this error

Traceback (most recent call last):
       16: from /usr/local/rvm/gems/ruby-2.6.5/gems/activesupport-4.2.11.1/lib/active_support/dependencies.rb:268:in `load'
       15: from /usr/local/rvm/gems/ruby-2.6.5/gems/activesupport-4.2.11.1/lib/active_support/dependencies.rb:240:in `load_dependency'
       14: from /usr/local/rvm/gems/ruby-2.6.5/gems/activesupport-4.2.11.1/lib/active_support/dependencies.rb:268:in `block in load'
       13: from /usr/local/rvm/gems/ruby-2.6.5/gems/bootsnap-1.4.8/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:77:in `load'
       12: from /usr/local/rvm/gems/ruby-2.6.5/gems/bootsnap-1.4.8/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:77:in `load'
       11: from {our repo}/stupidedi_notes_split.rb:109:in `<main>'
       10: from /usr/local/rvm/gems/ruby-2.6.5/gems/stupidedi-1.4.0/lib/stupidedi/either.rb:126:in `tap'
        9: from /usr/local/rvm/gems/ruby-2.6.5/gems/stupidedi-1.4.0/lib/stupidedi/either.rb:151:in `deconstruct'
        8: from {our repo}/stupidedi_notes_split.rb:110:in `block in <main>'
        7: from {our repo}/stupidedi_notes_split.rb:16:in `split'
        6: from /usr/local/rvm/gems/ruby-2.6.5/gems/stupidedi-1.4.0/lib/stupidedi/either.rb:126:in `tap'
        5: from /usr/local/rvm/gems/ruby-2.6.5/gems/stupidedi-1.4.0/lib/stupidedi/either.rb:151:in `deconstruct'
        4: from {our repo}/stupidedi_notes_split.rb:17:in `block in split'
        3: from {our repo}/stupidedi_notes_split.rb:56:in `only'
        2: from {our repo}/stupidedi_notes_split.rb:56:in `map'
        1: from {our repo}/stupidedi_notes_split.rb:91:in `block in only'
NoMethodError (undefined method `bind' for #<Stupidedi::Zipper::RootCursor:0x0000557e5f7f70f0>)

on this line _value = _value.up.bind{|z| z.replace(z.node.copy(:children => vaunts)) }.child(offset).

I'm wondering if this script is recoverable or the internal architecture of the stupidedi parsing library is too far changed. What would it take to get this working again?

FWIW I also got these deprecation warnings when I ran the script, indicating that this script was likely out of date and I hadn't missed anything:

DEPRECATION WARNING: Stupidedi::TransactionSets::FiftyTen::Implementations::X221::HP835 is deprecated, use X221A1::HP835 instead
DEPRECATION WARNING: Stupidedi::Builder is depecated, use Stupidedi::Parser instead
kputnam commented 3 years ago

Hi Robert,

Yes I believe the script should be salvageable. It looks like _value.up was assumed to return an Either<Zipper>, but the documentation for AbstractCursor#up shows it returns AbstractCursor. That has been the case at least since 0add6933, which is the 173-rd commit, so that example script has been broken forever 🤦‍♂️

The implementation of RootCursor#up throws an exception, rather than return Either.failure("root has no parent"), so you can transform it from expr.bind{|x| f(x) } to f(expr). If you're using Ruby 2.6+, you can also change it to expr.then{|x| f(x) }. You'll need to do the same thing for the next two lines _state = ....bind{ ... } and state.bind{ ... }, but it seemed to work for me.

To give some background, the idea behind Either#bind is that the receiver might be an error value (e.g., trying to get the parent of the root of the tree), it which case the block wouldn't be evaluated. In newer versions of Ruby, this is similar to #then. My rule of thumb is to return an Either.failure for a run-time issue that needs to be anticipated by the caller, and throw an exception for code that shouldn't have been called in the first place (upcoming Ruby type systems might help in making those errors reported at compile-time).

One thing I need to warn you of: that script was intended to split up large files to reduce memory consumption. It doesn't work because the entire input is still run through the tokenizer (which I've determined is the memory hog). You might have other reasons for splitting files though.

While it's taking me forever, I am working on dramatically improving that in this branch. When that is merged, splitting up the input can be done much more easily, something closer to this, which only uses the tokenizer without parsing and building the syntax tree.

rmlrmlrmlrml commented 3 years ago

Sorry for the late response; was finally able to get back focused on this subproject of ours.

Thanks for the fix, worked like a charm!

kputnam commented 3 years ago

Glad it worked!