Playing around with Ansible a little more. yum and service module were the easiest to use, and I think it would be the core moduel when provisioning a node. For a typical application I think git module is also a well-used one.
I’ve originally being setting up my servers with a pretty lengthy shell script that installs packages, clones git repos, chmods certain files and directories, and starts up designated services. Something like this:

yum -y install httpd
yum -y install php-devel


git clone /path/to/git-repo

chown user:user /path/to/git-repo/something
chmod 755 /path/to/git-repo/something

service httpd start

chmod and chown can be dealt with with the file module in Ansible. git clone and yum install and service is as I’ve mentioned.
What’s the ? Something like this:

expect -c "
        spawn sudo pecl install zmq channel:// 
        expect {
                \"Please provide\" { send \"\r\" }

rm /etc/php.d/zmq.ini
echo "" | tee /etc/php.d/zmq.ini

The expect, pecl and echo are not simple modules that come out of the box of Ansible, so here is a playbook I came up with.

- hosts: test-server
  sudo: yes
  - name: be sure zmq is installed
    yum: name=zeromq3 state=installed enablerepo=epel
  - name: be sure pecl (php-pear) is installed
    yum: name=php-pear state=installed

  - name: check zmq PECL existence (/etc/php.d/zmq.ini) 
    register: zmq_existence
    shell: cat /etc/php.d/zmq.ini 2> /dev/null
    changed_when: false  
    always_run: yes 
    ignore_errors: yes

  - name: be sure zmq PECL is installed
    shell: /path/to/install-zmq.expect
    when: zmq_existence.stdout.find('') == -1

  - name: add into /etc/php.d/
    shell: echo "" | tee /etc/php.d/zmq.ini
    when: zmq_existence.stdout.find('') == -1

I check if the zmq.ini is installed by cating and checking. ignore_errors is set to suppress the failure of cat, and the result will be registered in register: zmq_existence.
The next two tasks will check the existence with when: zmq_existence.stdout.find('') == -1, so that it is only executed when the zmq.ini does NOT exist. This is an important point, as it guarantees idempotence of these shell tasks.

The only part I don’t like about this is that I am not able to write the expect command directly in the playbook; I am calling an external shell script. I wish there is a way to handle expects in a smart way inside the playbook - will look into this.