I usually explain ROS in the following way:
ROS = plumbing + tools + capabilities + ecosystem
plumbing: ROS provides publish-subscribe messaging infrastructure designed to support the quick and easy construction of distributed computing systems.
tools: ROS provides an extensive set of tools for configuring, starting, introspecting, debugging, visualizing, logging, testing, and stopping distributed computing systems.
capabilities: ROS provides a broad collection of libraries that implement useful robot functionality, with a focus on mobility, manipulation, and perception.
ecosystem: ROS is supported and improved by a large community, with a strong focus on integration and documentation. ros.org is a one-stop-shop for finding and learning about the thousands of ROS packages that are available from developers around the world.
In the early days, the plumbing, tools, and capabilities were tightly coupled, which has both advantages and disadvantages. On the one hand, by making strong assumptions about how a particular component will be used, developers are able to quickly and easily build and test complex integrated systems. On the other hand, users are given an "all or nothing" choice: to use an interesting ROS component, you pretty much had to jump in to using all of ROS.
Four years in, the core system has matured considerably, and we're hard at work refactoring code to separate plumbing from tools from capabilities, so that each may be used in isolation. In particular, we're aiming for important libraries that were developed within ROS to become available to non-ROS users in a minimal-dependency fashion (as has already happened with OMPL and PCL).