Create macro using xparse that creates spaces between arguments

Fundamentally you want to condition on the existence of your optional arguments. In xparse this is done using \IfValueTF with the TF being optional on whether or not you need a True or False branch.

enter image description here

\documentclass{article}

\usepackage{xparse,amsmath}

\NewDocumentCommand\units{ o o o }{%
  \IfValueT{#1}{\;#1}%
  \IfValueT{#2}{\,#2}%
  \IfValueT{#3}{\,#3}%
}

\begin{document}

This pumpkin weighs $3\units[\text{kg}]$. That's heavy!

I can run $12\units[\text{m}][\text{s}^{-1}]$. That's fast!

Something ridiculous $1\units[a][b][c]$. That's ridiculous!

Something $5\units$ something else.

\end{document}

In general, units should be set like regular text.


A far better approach would be to use siunitx:

enter image description here

\documentclass{article}

\usepackage{siunitx}

\DeclareSIUnit{\aaa}{a}
\DeclareSIUnit{\bbb}{b}
\DeclareSIUnit{\ccc}{c}

\begin{document}

This pumpkin weighs $\SI{3}{\kilogram}$. That's heavy!

I can run $\SI{12}{\metre\per\second}$. That's fast!

Something ridiculous $\SI{1}{\aaa \bbb \ccc}$. That's ridiculous!

Something $5$ something else.

\end{document}

What if you have more than three units? Here units are separated by spaces, then the macro takes care of using thin spaces.

\documentclass{article}

\usepackage{xparse,amsmath}

\NewDocumentCommand\units{>{\SplitList{ }}m}{%
  \ProcessList{#1}{\addunit}%
}
\NewDocumentCommand{\addunit}{m}{%
  \,\mathrm{#1}%
}

\begin{document}

This pumpkin weighs $3\units{kg}$. That's heavy!

I can run $12\units{m s^{-1}}$. That's fast!

Something ridiculous $1\units{a b c}$. That's ridiculous!

\end{document}

enter image description here

Of course, siunitx is far better.