[MacRuby-devel] macruby/hotcocoa questions

Gary Weaver gary.weaver at duke.edu
Fri Feb 19 12:21:59 PST 2010


To answer some of my own questions or present new ones:

I gave up on Marshal to file and back for now. Laurent told me that 
active_support is planned to be supported in MacRuby 0.6, so instead of 
using to_xml/from_xml or to_json/from_json, I took Isaac Kearse's advice 
and looked into using plist included in HotCocoa.

I noticed that the read_plist method in HotCocoa 0.5.1 is on the 
HotCocoa module as an instance method which would mean I would need to 
include HotCocoa in Hash, Array, etc. to call it on one of those 
classes, so I did the following to be sure I had both methods on Object 
itself:


# HotCocoa 0.5.1 puts a to_plist on Object but a from_plist on HotCocoa. 
Having to include HotCocoa in your object in order to call read_plist is 
not intuitive and
# may cause adverse effects if having to extend Hash, Array, or Object 
with include HotCocoa. So instead, we add the same implementation plus a 
few lines to support
# reading from files, etc. like from_json/from_xml in ActiveSupport 
implementations do. While at first Object doesn't seem an appropriate 
place to put this method,
# it allows any object to have a from_plist class method as a companion 
to the to_plist instance method, which is intuitive. Examples:
# Hash.from_plist({:data=>'mydata'}.to_plist), 
Array.from_plist(['x','y','z'].to_plist), 
AnObject.from_plist(an_object.to_plist)
class Object
 
  # from_plist is the same as the HotCocoa 0.5.1 version. Could remove 
it, but keeping it here for now, in case need to debug.
  def self.from_plist(data, mutability=:all)
    # not sure if this will work
    if data.respond_to?(:read)
      data = data.read
    end
    mutability = case mutability
      when :none
        NSPropertyListImmutable
      when :containers_only
        NSPropertyListMutableContainers
      when :all
        NSPropertyListMutableContainersAndLeaves
      else
        raise ArgumentError, "invalid mutability `#{mutability}'"
    end
    if data.is_a?(String)
      data = data.dataUsingEncoding(NSUTF8StringEncoding)
      if data.nil?
        raise ArgumentError, "cannot convert string `#{data}' to data"
      end
    end
    #error = Pointer.new(:object)
    result = NSPropertyListSerialization.propertyListFromData(data,
      mutabilityOption:mutability,
      format:nil,
      errorDescription:nil)
    #raise error[0] if error[0].to_s.size > 0
  end
 
  # NSPropertyListSerialization can only take NSData, NSString, 
NSNumber, NSDate, NSArray, or NSDictionary object. Container objects 
must also contain only these kinds of objects.
  # So you must convert everything to either these types or hashes, 
arrays, strings, and other simple types before to_plist.
  def to_plist(format=:xml)
    format = case format
      when :xml
        NSPropertyListXMLFormat_v1_0
      when :binary
        NSPropertyListBinaryFormat_v1_0
      when :open_step
        NSPropertyListOpenStepFormat
      else
        raise ArgumentError, "invalid format `#{format}'"
    end
    #error = Pointer.new(:object)
    data = NSPropertyListSerialization.dataFromPropertyList(self,
      format:format,
      errorDescription:nil)
    #raise error[0] if error[0].to_s.size > 0
    NSMutableString.alloc.initWithData(data, encoding:NSUTF8StringEncoding)
  end
 
end


I also tried out those lines commented above to get the errors currently 
swallowed from NSPropertyListSerialization, but didn't get much out of that.

I also learned that those methods on NSPropertyListSerialization don't 
support nils or custom class instances, so I ended up writing some 
methods to convert my data into a hash containing array of hashes 
without any nil values in order to be able to have the to_plist and 
from_plist work. It would be nice if this supported custom types (custom 
class instances) and nils the way that activesupport's to_xml/from_xml 
do (I think), but I didn't have time to work out a solution to that.

And for now I just made closing the window exit the app. I wrote it so 
that if you start the app and start a task and kill the app, the task is 
still active and timer works even when computer is off (since it is 
storing the start_time of the task). It is very simplistic, but it works.

So yay, a working standlone multiple-timer application in 
HotCocoa/MacRuby! Let me know if you have any thoughts on this.

Thanks,
Gary


Gary Weaver wrote:
> Hello,
>
> I wrote a small application in HotCocoa/MacRuby just to get familiar 
> with it ( http://github.com/garysweaver/hourz ). MacRuby and HotCocoa 
> are awesome! I did have a few issues during development that I thought 
> I'd share in case anyone can assist.
>
> I'm using MacRuby 0.5 and HotCocoa 0.5.1 on OS X 10.6.2, was using 
> TextMate vs. XCode to develop it. I have some experience with Ruby, 
> but consider me a newbie to MacRuby, HotCocoa, and Cocoa (and Obj-C 
> for that matter).
>
> Here is what I ran into:
>
> * If I take a stringValue from a text field, Marshal.dump it to a 
> file, and then Marshal.load it, and put it back into the text field, 
> it puts wierd characters in the end of the value like 'Òÿýÿÿÿ'. I 
> think this might be a result of the class that I'm Marshalling that 
> contains "include HotCocoa::Behaviors"? Not sure. I wasn't able to 
> reproduce the issue via macirb using simple array or array of simple 
> custom class Marshalling to file and back, but I'm able to reproduce 
> the issue everytime in my app, but the class is more complicated.
>
> * I wasn't able to get File.copy to work so I wrote my own method to 
> copy a file. Could you provide an example that can copy a file in 
> MacRuby using File.copy or using FileUtils?
>
> * I wasn't able to set the (HotCocoa) layout_view frame or hidden 
> properties successfully via calls by a button on_action. I could set 
> them fine as long as they were called during startup of the 
> application. For example, I wanted to do the following to hide a 
> layout_view and replace it with another layout_view and vice versa in 
> the same area of the window, but these methods only worked if being 
> called during the initial load. I'm thinking maybe there is some sort 
> of refresh method I need to call?
>
>  def in_add_mode
>    @edit_view.frame = [0, 0, 0, 0]
>    @edit_view.hidden = true
>    @add_view.frame = [0, 0, 0, 40]
>    @add_view.hidden = false
>  end
>
>  def in_edit_mode
>    @add_view.frame = [0, 0, 0, 0]
>    @add_view.hidden = true
>    @edit_view.frame = [0, 0, 0, 40]
>    @edit_view.hidden = false
>    # ...
>  end
>
> * (window).will_miniaturize { exit } works great to keep the app 
> active (in the dock) after closing the window, but I don't know what 
> to call such that I could close the window and then click on the icon 
> in the dock it then show the window. Also when I close it, it doesn't 
> appear to be in the hidden state, because the dock menu indicates that 
> I can hide the window (but it is hidden).
>
> * I couldn't figure out how to access the dock_menu in 
> HotCocoa/MacRuby (I'm not using XCode or 
> http://www.echographia.com/blog/2009/02/08/dynamic-dock-menus-in-macruby/ 
> would have helped). I'd like to be able to manage it dynamically in 
> HotCocoa if possible to be able to choose which Task I'm working on at 
> the moment without showing the window. It would also be cool to 
> dynamically change the dock icon when this happens to somehow indicate 
> which task is being worked on (similar to Thunderbird showing the 
> number of new messages, maybe I could show a number or some brief text?).
>
> * I couldn't figure out how to alter the "About" part of the 
> application to provide the authorship, license, and link to the 
> project, although I know the version number is specified in 
> config/build.yml. It would also be cool to have full control over that 
> area and define the window, etc.
>
> * I wasn't sure what the best practice would be to ensure that the 
> window could be resized if someone somehow is using larger/smaller 
> fonts, but to keep it from being resized so much that it is unusable. 
> Maybe the right thing to do is to just specify a defined size/frame 
> for the window that cannot be changed?
>
> * Note that I might also look into storing the task data as xml or 
> json. I'd rather it be hand-editable if needed. (I assume I could just 
> put the array into a hash and use to_xml/from_xml or to_json/from_json.)
>
> Again, thanks so much for all of your work on this. It is really cool 
> to develop apps for OS X this quickly! (<16 hours total dev time, not 
> including time to post to GitHub, and a lot of that was research, 
> documentation, making an icon, etc.)
>
> Thanks in advance for any assistance!
>
> Gary
> _______________________________________________
> MacRuby-devel mailing list
> MacRuby-devel at lists.macosforge.org
> http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel



More information about the MacRuby-devel mailing list