unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* Iterating over buffer lines
@ 2023-06-16 22:19 Joshua Lambert
  2023-06-17  0:10 ` Platon Pronko
  0 siblings, 1 reply; 6+ messages in thread
From: Joshua Lambert @ 2023-06-16 22:19 UTC (permalink / raw)
  To: help-gnu-emacs

I have created some functions that make changes to one buffer line of
a csv file. Let's call those functions a, b and c. Each of those take
one or more arguments. I want to create a separate interactive
function that does what function a, b, and c do, but on every line of
the region. I successfully created a function (act-on-region-by-line)
to go through all lines in a region and then call function a, function
b, or function c. But, It seems redundant to have multiple functions
that have 9-15 lines similar and one line different, the one that
specifies function a, b or c. What is the best way to be efficient in
this situation?

I have attempted to pass function b as a parameter, but I am slow to
understand how to do that. Is that the best way, or is there another?

Thanks,
J Lambert



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iterating over buffer lines
  2023-06-16 22:19 Iterating over buffer lines Joshua Lambert
@ 2023-06-17  0:10 ` Platon Pronko
  2023-06-17  3:28   ` Joshua Lambert
  0 siblings, 1 reply; 6+ messages in thread
From: Platon Pronko @ 2023-06-17  0:10 UTC (permalink / raw)
  To: Joshua Lambert, help-gnu-emacs

On 2023-06-17 06:19, Joshua Lambert wrote:
> I have created some functions that make changes to one buffer line of
> a csv file. Let's call those functions a, b and c. Each of those take
> one or more arguments. I want to create a separate interactive
> function that does what function a, b, and c do, but on every line of
> the region. I successfully created a function (act-on-region-by-line)
> to go through all lines in a region and then call function a, function
> b, or function c. But, It seems redundant to have multiple functions
> that have 9-15 lines similar and one line different, the one that
> specifies function a, b or c. What is the best way to be efficient in
> this situation?
> 
> I have attempted to pass function b as a parameter, but I am slow to
> understand how to do that. Is that the best way, or is there another?
> 
> Thanks,
> J Lambert
> 

It's a bit difficult to understand what the problem is without seeing the code. Can you show the code for your latest attempt?

Yes, passing function as a parameter seems to be the best way. And partial function application might be useful here as well.

-- 
Best regards,
Platon Pronko
PGP 2A62D77A7A2CB94E




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iterating over buffer lines
  2023-06-17  0:10 ` Platon Pronko
@ 2023-06-17  3:28   ` Joshua Lambert
  2023-06-17  4:48     ` tomas
  2023-06-18  1:17     ` Platon Pronko
  0 siblings, 2 replies; 6+ messages in thread
From: Joshua Lambert @ 2023-06-17  3:28 UTC (permalink / raw)
  To: Platon Pronko; +Cc: help-gnu-emacs

OK. See below. I'm trying to avoid reusing most of the code in
function my-act-on-region-by-line. There are multiple functions that
correct data errors in a csv file and I want to be able to
interactively run one of those corrections at a time. The resulting
string will be inserted at the beginning of each line. That all works,
I'm just trying not to have so much code repetition.

(defun my-act-on-region-by-line (some-function &optional beg end)
  "Perform a function on the current line or each line of the region.
Each SOME-FUNCTION must return a string."
  (let ((beg2 (if (region-active-p)
                        beg
                      (line-beginning-position)))
          (end2 (if (region-active-p)
                         end
                      (line-end-position))))
    (save-excursion
      (save-restriction
         (narrow-to-region beg2 end2)
         (goto-char (point-min))
         (while (not (eobp))
            (goto-char (line-beginning-position))
            (insert some-chosen-function) ;; Inserts text after a
function transforms it.
            (insert my-separator)
            (forward-line)))))

(defun my-paste-corrected-spacing (&optional field-num beg end)
  "Correct spacing in a string and paste it at the beginning of a line.
Interactively, BEG and END are the region."
  (interactive "*p\nr")
  (my-act-on-region-by-line (some-function-to-correct-spacing field-num)
   beg
   end))

(defun some-function-to-correct-spacing (field-num)
  "Function that creates a correctly spaced string."
  ........

On Fri, Jun 16, 2023 at 7:10 PM Platon Pronko <platon7pronko@gmail.com> wrote:
>
> On 2023-06-17 06:19, Joshua Lambert wrote:
> > I have created some functions that make changes to one buffer line of
> > a csv file. Let's call those functions a, b and c. Each of those take
> > one or more arguments. I want to create a separate interactive
> > function that does what function a, b, and c do, but on every line of
> > the region. I successfully created a function (act-on-region-by-line)
> > to go through all lines in a region and then call function a, function
> > b, or function c. But, It seems redundant to have multiple functions
> > that have 9-15 lines similar and one line different, the one that
> > specifies function a, b or c. What is the best way to be efficient in
> > this situation?
> >
> > I have attempted to pass function b as a parameter, but I am slow to
> > understand how to do that. Is that the best way, or is there another?
> >
> > Thanks,
> > J Lambert
> >
>
> It's a bit difficult to understand what the problem is without seeing the code. Can you show the code for your latest attempt?
>
> Yes, passing function as a parameter seems to be the best way. And partial function application might be useful here as well.
>
> --
> Best regards,
> Platon Pronko
> PGP 2A62D77A7A2CB94E
>



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iterating over buffer lines
  2023-06-17  3:28   ` Joshua Lambert
@ 2023-06-17  4:48     ` tomas
       [not found]       ` <CAGGu9j1gub_8kb92kkD30QmxLmZz8XJrwhyAPtYONE3OLe_zew@mail.gmail.com>
  2023-06-18  1:17     ` Platon Pronko
  1 sibling, 1 reply; 6+ messages in thread
From: tomas @ 2023-06-17  4:48 UTC (permalink / raw)
  To: Joshua Lambert; +Cc: Platon Pronko, help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 2422 bytes --]

On Fri, Jun 16, 2023 at 10:28:45PM -0500, Joshua Lambert wrote:
> OK. See below. I'm trying to avoid reusing most of the code in
> function my-act-on-region-by-line. There are multiple functions that
> correct data errors in a csv file and I want to be able to
> interactively run one of those corrections at a time. The resulting
> string will be inserted at the beginning of each line. That all works,
> I'm just trying not to have so much code repetition.
> 
> (defun my-act-on-region-by-line (some-function &optional beg end)
>   "Perform a function on the current line or each line of the region.
> Each SOME-FUNCTION must return a string."
>   (let ((beg2 (if (region-active-p)
>                         beg
>                       (line-beginning-position)))
>           (end2 (if (region-active-p)
>                          end
>                       (line-end-position))))
>     (save-excursion
>       (save-restriction
>          (narrow-to-region beg2 end2)
>          (goto-char (point-min))
>          (while (not (eobp))
>             (goto-char (line-beginning-position))
>             (insert some-chosen-function) ;; Inserts text after a
> function transforms it.
>             (insert my-separator)

The above means that you are inserting stuff at the beginning of the
current line, right?

>             (forward-line)))))

... and this assumes that your `some-chosen-function' doesn't mess
"too much" with point.

> 
> (defun my-paste-corrected-spacing (&optional field-num beg end)
>   "Correct spacing in a string and paste it at the beginning of a line.
> Interactively, BEG and END are the region."
>   (interactive "*p\nr")
>   (my-act-on-region-by-line (some-function-to-correct-spacing field-num)
>    beg
>    end))
> 
> (defun some-function-to-correct-spacing (field-num)
>   "Function that creates a correctly spaced string."
>   ........

I can't /see/ it, but I have a hunch that this function expects
to /replace/ the line by something else. The was it is called
above, its result is /inserted/ in front of the line in question,
right?

Perhaps it's clear to you, but if yes, it doesn't come across:
what is the exact interface between your outer function and
the one called by it?

I.e.: do you need to (save-excursion ...) around `some-chosen-function'?
What do you do with its result? That kind of things.

Cheers
-- 
t

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iterating over buffer lines
       [not found]       ` <CAGGu9j1gub_8kb92kkD30QmxLmZz8XJrwhyAPtYONE3OLe_zew@mail.gmail.com>
@ 2023-06-17 19:17         ` tomas
  0 siblings, 0 replies; 6+ messages in thread
From: tomas @ 2023-06-17 19:17 UTC (permalink / raw)
  To: Joshua Lambert; +Cc: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 2199 bytes --]

(I re-added the list to the CC: I guess you are interested
in getting some help, and I'm not necessarily the best at
this)

On Sat, Jun 17, 2023 at 09:09:37AM -0500, Joshua Lambert wrote:
> On Fri, Jun 16, 2023 at 11:48 PM <tomas@tuxteam.de> wrote:
> >
> > The above means that you are inserting stuff at the beginning of the
> > current line, right?
> 
> Yes. That is correct.

OK.

[...]

> > I.e.: do you need to (save-excursion ...) around `some-chosen-function'?
> > What do you do with its result? That kind of things.
> >
> Sorry I have not sent enough or the correct information. I may not
> need to save the excursion but it is a nice user feature I would like
> to keep.

If you have your "protocol" clear, that's fine :-)

> The function that follows works like I want but is very repetitive
> given what I mention below. In order for me to run various data
> cleanup processes, I exchange the (my-string-pad-concat
> (my-get-string-from-line field-num)) with other function calls. One
> correctly pads a string as needed. (this is internal padding that has
> to follow complicated logic.) Another removes unneeded spaces from
> other strings. So forth. Each of those provides a string to be
> inserted at the beginning of each line.
> 
> (defun my-make-region-sortable (&optional field-num beg end)
>   "Create a padded string for each line in region.
>   Interactively, BEG and END are the region."
>   (interactive "*p\nr")
>   (let ((beg2 (if (region-active-p)
>                          beg
>                       (line-beginning-position)))
>            (end2 (if (region-active-p)
>                            end
>                        (line-end-position))))
>      (save-excursion
>        (save-restriction
>          (narrow-to-region beg2 end2)
>          (goto-char (point-min))
>          (while (not (eobp))
>            (goto-char (line-beginning-position))
>            (insert (my-string-pad-concat (my-get-string-from-line field-num)))
>            (insert string-separator)
>            (forward-line))))))

Hm. So you want to pass an extra arg to call where `my-string-pad-concat ...' is?

Cheers
-- 
t

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iterating over buffer lines
  2023-06-17  3:28   ` Joshua Lambert
  2023-06-17  4:48     ` tomas
@ 2023-06-18  1:17     ` Platon Pronko
  1 sibling, 0 replies; 6+ messages in thread
From: Platon Pronko @ 2023-06-18  1:17 UTC (permalink / raw)
  To: Joshua Lambert; +Cc: help-gnu-emacs

On 2023-06-17 11:28, Joshua Lambert wrote:
> OK. See below. I'm trying to avoid reusing most of the code in
> function my-act-on-region-by-line. There are multiple functions that
> correct data errors in a csv file and I want to be able to
> interactively run one of those corrections at a time. The resulting
> string will be inserted at the beginning of each line. That all works,
> I'm just trying not to have so much code repetition.
> 
> (defun my-act-on-region-by-line (some-function &optional beg end)
>    "Perform a function on the current line or each line of the region.
> Each SOME-FUNCTION must return a string."
>    (let ((beg2 (if (region-active-p)
>                          beg
>                        (line-beginning-position)))
>            (end2 (if (region-active-p)
>                           end
>                        (line-end-position))))
>      (save-excursion
>        (save-restriction
>           (narrow-to-region beg2 end2)
>           (goto-char (point-min))
>           (while (not (eobp))
>              (goto-char (line-beginning-position))
>              (insert some-chosen-function) ;; Inserts text after a
> function transforms it.
>              (insert my-separator)
>              (forward-line)))))
> 
> (defun my-paste-corrected-spacing (&optional field-num beg end)
>    "Correct spacing in a string and paste it at the beginning of a line.
> Interactively, BEG and END are the region."
>    (interactive "*p\nr")
>    (my-act-on-region-by-line (some-function-to-correct-spacing field-num)
>     beg
>     end))
> 
> (defun some-function-to-correct-spacing (field-num)
>    "Function that creates a correctly spaced string."
>    ........
> 

The code you pasted doesn't seem to work, for example because some-chosen-function doesn't exist. So I have trouble understanding what your problem is - is the pasted code fragment the example of duplication, or your approach to reducing duplication in code that I don't see?

If it's example of duplication (between my-paste-corrected-spacing and some other similar functions), then it looks like the duplication is minimal - function name, docstring, and underlying function are different. So actual duplication is 2-3 lines - `(&optional field-num beg end)`, `(interactive "*p\nr")`, and `my-act-on-region-by-line` parts. You can create a macro to reduce that duplication even further, but it seems that we are hitting diminishing returns here.

If the code as shown is already an attempt to reduce duplication then it looks like you are almost there - you just need to use `(apply some-function)` to call the function that you pass to my-act-on-region-by-line.



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-06-18  1:17 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-06-16 22:19 Iterating over buffer lines Joshua Lambert
2023-06-17  0:10 ` Platon Pronko
2023-06-17  3:28   ` Joshua Lambert
2023-06-17  4:48     ` tomas
     [not found]       ` <CAGGu9j1gub_8kb92kkD30QmxLmZz8XJrwhyAPtYONE3OLe_zew@mail.gmail.com>
2023-06-17 19:17         ` tomas
2023-06-18  1:17     ` Platon Pronko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).