107

How do I define an array of anonymous objects in CoffeeScript? Is this possible at all, using the YAML syntax?

I know that having an array of named objects is quite easy:

items:[
   item1:
      name1:value1
   item2:
      name:value2
]

However, it would be a bit trickier, if those two objects had no names

John Sheehan
  • 77,456
  • 30
  • 160
  • 194
Preslav Rachev
  • 3,983
  • 6
  • 39
  • 63

9 Answers9

306

Simple -- place a comma by itself in a column lower than that in which you define your objects.

a = [
     nameA1: valueA1
     nameA2: valueA2
     nameA3: valueA3
  ,
     nameB1: valueB1
     nameB2: valueB2
     nameB3: valueB3
]

Will become:

var a;

a = [
  {
    nameA1: valueA1,
    nameA2: valueA2,
    nameA3: valueA3
  }, {
    nameB1: valueB1,
    nameB2: valueB2,
    nameB3: valueB3
  }
];
Michael Hays
  • 6,878
  • 2
  • 21
  • 17
  • 1
    because its a weird lookin solution and the commas are easily missed – Eddie Monge Jr Oct 03 '13 at 23:29
  • This is dangerous!! Sometimes only gives you an array with the last item ! See my example below.. – Dean Radcliffe Oct 11 '13 at 19:41
  • 1
    @DeanRadcliffe It will return the last item in the array if you don't place the comma properly, yes, but isn't CoffeeScript built on the premise of convention over syntactical sugar? – dubilla Jan 16 '14 at 21:42
  • I would indent the opening `[` to the left of the next line, it's confusing enough as is.. – matanster Aug 06 '14 at 22:20
  • 4
    I think coffeescript, instead of being a simplification and improvement over vanilla generates a lot more unnecessary complications. Would love to use just plain .js with rails integration without the need for coffee. – LasagnaAndroid Oct 14 '14 at 18:16
  • I think this is less dangerous if you align the comma with the a. It seems odd to me to have something not aligned with a tab, which is the case in this answer, I believe. – Gaz Sep 15 '15 at 15:53
  • @Gaz Good point! While the amount of white space is a matter of taste and doesn't change the output of this code, I feel that your suggestion would improve the readability of what I've submitted. I've adjusted my answer to align things to 2-space tabs. Thank you! – Michael Hays Jan 11 '16 at 21:28
41

You can also add a coma between each object: 

items:[
    item1:
        name1:value1
  ,
    item2:
        name:value2
]
arthur
  • 950
  • 1
  • 5
  • 18
27

you can't:

this is some tricks:

items:[
    (name:"value1")
    (name:"value2")
]

another

items:[
    true && name:"value1"
    true && name:"value2"
]

this is the best:

items:[
    {name:"value1"}
    {name:"value2"}
]
island205
  • 1,730
  • 17
  • 28
  • 6
    Isn't that so ugly :( Coffeescript is really nice for it's indent based coding but for large object literals it's not much better than standard JSON as you have to balance up all the brackets and you end up with nasty trailing bracket soup. There was a ticket to resolve this and use YAML syntax but apparently there is parsing ambiguity in coffeescript to solve this which is unfortunate. – bradgonesurfing Apr 16 '12 at 16:46
  • Instead of "true &&" you could of course use the equivalent "yes and" or "no or". "yes and" even kind of makes sense here. – Jameson Quinn Dec 03 '12 at 03:04
  • 18
    Check out my answer -- this is perfectly doable without any tricks or braces. – Michael Hays Dec 27 '12 at 18:15
14

I think the comma solution is better, but I figured I'd add this for completeness:

a = [
  {
    nameA1: valueA1
    nameA2: valueA2
    nameA3: valueA3
  }
  {
    nameB1: valueB1
    nameB2: valueB2
    nameB3: valueB3
  }
]
Evan Moran
  • 3,825
  • 34
  • 20
  • I think this is much better than the comma solution, where you have to be careful with comma placement. – nima Sep 05 '15 at 06:50
3

You can define variable while defining array, so an ugly answer would be:

a = 
  items: [
    item1 = 
      name: 'value1'
    item2 = 
      name: 'value2'
  ]

It would work, but you may get warnings about "defined, but not used variables (item1, item2)". Better way would be to use underscore, variable used to omit not used variables:

a = 
  items: [
    _ = 
      name: 'value1'
    _ = 
      name: 'value2'
  ]

console.log JSON.stringify(a) will produce this:

  {
    "items":[
      {
        "name":"value1"
      },{
        "name":"value2"
      }
    ]
  }
remiq
  • 136
  • 4
1

I'm very happy to report after a bit of fiddling that I could get this to compile just right:

items: [
  nameA: subA
  nameB: subB
,
  nameX: subX
  nameY: subY
]

It results it just what you'd expect: a list of two anonymous objects.

Prathan Thananart
  • 4,007
  • 3
  • 19
  • 18
0

I ran into a related problem and found this solution. If you want an array of many single k/v objects without braces, just indent some of them. Seems to do the trick.

data = [                                     
  "2013-09-25T16:46:52.636Z":3,              
    "2013-09-25T16:47:52.636Z":6,            
      "2013-09-25T16:48:52.636Z":2,          
        "2013-09-25T16:49:52.636Z":7,        
  "2013-09-25T16:50:52.636Z":5,              
    "2013-09-25T16:51:52.636Z":2,            
      "2013-09-25T16:52:52.636Z":1,          
        "2013-09-25T16:53:52.636Z":3,        
  "2013-09-25T16:54:52.636Z":8,              
    "2013-09-25T16:55:52.636Z":9,            
      "2013-09-25T16:56:52.636Z":2,          
        "2013-09-25T16:57:52.636Z":5,        
          "2013-09-25T16:58:52.636Z":7       
]                                            

Produces:

coffee> data
[ { '2013-09-25T16:46:52.636Z': 3 },
  { '2013-09-25T16:47:52.636Z': 6 },
  { '2013-09-25T16:48:52.636Z': 2 },
  { '2013-09-25T16:49:52.636Z': 7 },
  { '2013-09-25T16:50:52.636Z': 5 },
  { '2013-09-25T16:51:52.636Z': 2 },
  { '2013-09-25T16:52:52.636Z': 1 },
  { '2013-09-25T16:53:52.636Z': 3 },
  { '2013-09-25T16:54:52.636Z': 8 },
  { '2013-09-25T16:55:52.636Z': 9 },
  { '2013-09-25T16:56:52.636Z': 2 },
  { '2013-09-25T16:57:52.636Z': 5 },
  { '2013-09-25T16:58:52.636Z': 7 } ]

It's counter-intuitive to me; you'd think that this would make sub-objects but I think the comma at the end of the line tells it to stop making properties on that object.

jcollum
  • 43,623
  • 55
  • 191
  • 321
  • While this works, I suspect it is a side effect of how the lines are parsed. Since successive lines don't have the same indentation, it can't put them in the same object. Apparently, instead of raising a syntax error, it starts a new object. It's a feature that probably shouldn't be counted on - unless you can find it documented. – hpaulj Sep 25 '13 at 20:11
  • @hpaulj well if you've got a better way to do this I'm all ears – jcollum Sep 25 '13 at 20:55
  • 1
    Since `Python` is my 'first language', I'm not afraid to use a few extra brackets and braces. Even if Coffeescript does not need them, I find them to be helpful. Your second block is more readable. – hpaulj Sep 25 '13 at 22:28
0

Not an answer to the OP's question, but just in case you're here for the same reason I was... If you're low on Mountain Dew and use '=' instead of ':', then Coffeescript will turn your array of objects into a flat array without a compile error:

data = [
    one='one'
    two='two'
  ,
    one='1'
    two='2'
]

Produces

['one', 'two', '1', '2']

Insert more Mountain Dew and replace the '=' with ':'.

Seth
  • 6,514
  • 5
  • 49
  • 58
0

Why not:

list = []
list.push
  prop1: val
  prop2: val
list.push
  prop1: val
  prop2: val

It's still a huge improvement to me over js, very easy to read, minimal and pretty safe to write.

Guido Tarsia
  • 1,962
  • 4
  • 27
  • 45