Aptana Journal #9: Mengorbankan Static Method


Pada Journal #1, saya melakukan perubahan pada ParserUtil di method getParentObjectTypes() dimana saya menganggap seluruh referensi jQuery adalah ke Function<jQuery> bukan Class<jQuery>.  Dengan kata lain, saya menganggap semua penggunaan jQuery berdasarkan instance, misalnya: $("p").blur(). Padahal, pada kenyataannya, ada beberapa method jQuery yang dapat diakses tanpa harus membuat instance, misalnya: $.ajax().  Method seperti ini adalah method static.   Dengan pendekatan yang saya tempuh saat ini, seluruh method, baik yang static maupun per-instace, akan ditampilkan dalam content assist saat pengguna mengetik jQuery atau $.   Saya pikir trade-off ini masih dapat diterima bila dibandingkan dengan keuntungan yang saya peroleh saat melakukan coding jQuery nanti (membuat widget, misalnya).

jQuery mengandung beberapa definisi class yang dapat dipakai diluar, misalnya Callbacks, Deferred, dan jqXHR.  Kebanyakan dari class tersebut dapat dibuat dengan constructor berupa method static di object jQuery.   Karena saya tidak mendukung method static, maka saya mendokumentasikan seluruh constructor sebagai function biasa (per-instance).

Permasalahan yang saya hadapi adalah content assist tidak bekerja dengan baik untuk constructor tersebut.  Aptana Studio menganggap seluruh constructor tersebut mengembalikan sebuah Object yang universal.

Mengapa demikian?  Untuk menjawab pertanyaan ini, saya pun melakukan penelusuran, yang membawa saya pada class JSNodeTypeInferrer. Class ini memiliki sebuah method dengan nama visit() dimana berisi cuplikan seperti berikut ini:

public void visit(JSGetPropertyNode node)
{
   ... // kode diabaikan
   // TODO Combine with similiar code from ParseUtil.getParentObjectTypes
   if (JSTypeCOnstants.FUNCTION_JQUERY.equals(typeName)
          && lhs instanceof JSIdentifierNode
          && (JSTypeConstants.DOLLAR.equals(lhs.getText()) || JSTypeConstants.JQUERY.
                 .equals(lhs.getText())))
   {
       typeName = JSTypeConstants.CLASS_JQUERY;
   }
   ... // kode diabaikan
}

Wow!  Sesuai dengan komentar TODO di atas-nya,  disini telah terjadi duplikasi kode program.  Bila saya menghilangkan logic di ParseUtil.getParentObjectTypes() (petualangan di journal #1), maka saya WAJIB  menghilangkan bagian yang ini juga!  Ini bisa membingungkan orang-orang, terutama saya yang berasumsi bahwa perubahan pada ParseUtil sudah menyelesaikan masalah, tetapi disini juga perlu diubah.  Untuk itu, saya memberikan komentar pada baris di atas sehingga mereka tidak akan mengubah Function<jQuery> menjadi Class<jQuery>.

Tapi petualangan belum berakhir sampai disini.  Setelah tipe class bisa ditemukan dengan baik, Apatana Studio tetap tidak mengembalikan method yang spesifik untuk class tersebut, melainkan hanya class bersifat umum yaitu Object.

Mengapa demikian?  Penelusuran kode program membawa saya ke method addTypeProperties() di class JSContentAssistProcessor.  Pada method ini terdapat sebuah baris kode program seperti berikut ini:

Collection properties = indexHelper.getTypeMembers(index, allTypes);

Lalu, apa isi dari method getTypeMembers()? Isinya seperti berikut ini:

public Collection getTypeMembers(Index index, List<String> typeNames) {
return CollectionsUtil.union(getMembers(index, typeNames), getMembers(getIndex(), typeNames));
}

Pada saat melakukan tracing, masing-masing getMembers() telah mengembalikan method yang valid dan benar.  Tetapi pada saat keduanya digabungkan kedalam sebuah Set, selalu ada yang hilang!  Hal ini tiba-tiba mengingatkan saya pada ‘bug‘ yang saya temui di journal #4 sehubungan dengan nilai di Set yang menghilang.   Ternyata benar, class FunctionElement belum memiliki method equals() dan hashCode().  Saya segera memilih menu Source, Generate hashCode() and equals().

Sampai disini semua sudah mendingan, tapi petualangan belum berakhir.  Mengapa demikian?  Karena method yang muncul selalu terduplikasi, ada yang mengandung dokumentasi dan ada yang tidak.  Padahal, saya menginginkan hanya yang mengandung dokumentasi saja yang ditampilkan (dan tampilkan versi tidak terdokumentasi bila seandainya tidak ada yang lebih baik).

Untuk mengatasi permasalahan tersebut, saya mengubah method visit di JSNodeTypeInfererrer menjadi seperti:

public void visit(JSGetPropertyNode node)
{
   ... // kode program diabaikan
   if (properties!=null)
   {
      for (PropertyElement property: properties)
      {
          if (property instanceof FunctionElement)
          {
              FunctionElement function = (FunctionElement) property;
              boolean adaVersiTerdokumentasi = false;
              if (function.getDescription()==null || function.getDescription().length()==0) {
                  for (PropertyElement item: properties) {
                     if (item instanceof FunctionElement && item.getName().equals(function.getName()) && 
                         item.getDescription()!=null && item.getDescription().length()>0) {
                         adaVersiTerdokumentasi = true;
                     }
                  }
              }
              if (adaVersiTerdokumentasi) continue;

              ... // kode program diabaikan
          }

          ... // kode program diabaikan
      }
   }
}

Belajar dari petualangan hari ini, saya sudah beberapa kali melakukan filtering elemen yang mengandung dokumentasi.  Sepertinya logika ini bisa dikumpulkan ke sebuah class sehingga saat melakukan perubahan, saya cukup mengubah class tersebut.

Sekarang, saya akan melakukan pengujian, misalnya, saya akan memanggil method static Callback seperti berikut ini:

Menampilkan Content Assist Untuk $

Menampilkan Content Assist Untuk $

Context info untuk method tersebut akan muncul seperti yang terlihat di gambar berikut ini:

Menampilkan Context Info Untuk Callbacks

Menampilkan Context Info Untuk Callbacks

Setelah itu, bila saya memanggil salah satu method object Callbacks, maka content assist akan muncul, seperti berikut ini:

Menampilkan Content Assist Untuk  Object Callbacks

Menampilkan Content Assist Untuk Object Callbacks

Beruntungnya, content assist pada saat terjadi chaining tetap bekerja dengan baik seperti yang terlihat di gambar berikut ini:

Content  assist setelah method add di Calllbacks

Content assist setelah method add di Calllbacks

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: