rbpod 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,5 +1,7 @@
1
1
  *.gem
2
2
  *.rbc
3
+ *.so
4
+ *.swp
3
5
  .bundle
4
6
  .config
5
7
  .yardoc
data/README.md CHANGED
@@ -54,7 +54,7 @@ Functional for most read-only purposes.
54
54
  database.playlists.map(&:name) # => ["iPod", "Podcasts", "Recently Added"]
55
55
 
56
56
  # Track Listing (also enumerable)
57
- database.tracks.count # => 400
57
+ database.tracks.length # => 400
58
58
  database.tracks.first.artist # => "Steppenwolf"
59
59
  database.tracks.first.title # => "Born To Be Wild"
60
60
 
data/Rakefile CHANGED
@@ -1 +1,36 @@
1
- require "bundler/gem_tasks"
1
+ # Bring in rake with rake-compiler's support.
2
+ require 'rake'
3
+ require 'rake/extensiontask'
4
+
5
+ # Bring in bundler and it's gem tasks.
6
+ require 'bundler/setup'
7
+ require 'bundler/gem_tasks'
8
+
9
+ # Bring in RSpec's built-in rake task.
10
+ require 'rspec/core/rake_task'
11
+
12
+ # By default, clean, compile and then test.
13
+ task :default => [ :compile, :test ]
14
+
15
+ desc "Compile the native extension."
16
+ Rake::ExtensionTask.new do |extension|
17
+ # Some basic configuration.
18
+ extension.name = 'rbpod'
19
+ extension.ext_dir = 'ext/rbpod'
20
+ extension.lib_dir = 'lib/rbpod'
21
+
22
+ # Monitor sources for change tracking.
23
+ extension.source_pattern = '*.{c,h}'
24
+ end
25
+
26
+ desc "Run all available RSpec tests."
27
+ RSpec::Core::RakeTask.new(:test) do |task|
28
+ task.pattern = 'spec/**/*_spec.rb'
29
+ # Execute ruby with warnings enabled.
30
+ task.ruby_opts = '-w'
31
+ end
32
+
33
+ desc "Open a console with rbpod preloaded."
34
+ task :console => [ :compile ] do
35
+ sh 'bundle console'
36
+ end
data/bin/rbpod CHANGED
File without changes
@@ -7,14 +7,15 @@ VALUE cRbPodCollection;
7
7
 
8
8
  struct collection { VALUE klass; GList *list; };
9
9
 
10
- static inline struct collection *rbpod_collection_unwrap(VALUE self) {
11
- struct collection *collection = NULL;
12
- Data_Get_Struct(self, struct collection, collection);
13
- return collection;
10
+ inline VALUE rbpod_collection_create(GList *list, VALUE type) {
11
+ struct collection *collection = ALLOC(struct collection);
12
+ collection->list = list;
13
+ collection->klass = type;
14
+ return Data_Wrap_Struct(cRbPodCollection, NULL, NULL, (void *) collection);
14
15
  }
15
16
 
16
17
  static VALUE rbpod_collection_get(VALUE self, VALUE key) {
17
- struct collection *collection = rbpod_collection_unwrap(self);
18
+ struct collection *collection = TYPED_DATA_PTR(self, struct collection);
18
19
  GList *current = NULL;
19
20
 
20
21
  if (FIXNUM_P(key) == FALSE)
@@ -22,42 +23,41 @@ static VALUE rbpod_collection_get(VALUE self, VALUE key) {
22
23
 
23
24
  current = g_list_nth(collection->list, FIX2INT(key));
24
25
 
25
- return Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);;
26
+ return Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);
26
27
  }
27
28
 
28
29
  static VALUE rbpod_collection_last(VALUE self) {
29
- struct collection *collection = rbpod_collection_unwrap(self);
30
+ struct collection *collection = TYPED_DATA_PTR(self, struct collection);
30
31
  GList *current = g_list_last(collection->list);
31
32
  return Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);
32
33
  }
33
34
 
34
35
  static VALUE rbpod_collection_first(VALUE self) {
35
- struct collection *collection = rbpod_collection_unwrap(self);
36
+ struct collection *collection = TYPED_DATA_PTR(self, struct collection);
36
37
  GList *current = g_list_first(collection->list);
37
38
  return Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);
38
39
  }
39
40
 
40
- static VALUE rbpod_collection_count(VALUE self) {
41
- struct collection *collection = rbpod_collection_unwrap(self);
41
+ static VALUE rbpod_collection_length(VALUE self) {
42
+ struct collection *collection = TYPED_DATA_PTR(self, struct collection);
42
43
  return INT2NUM(g_list_length(collection->list));
43
44
  }
44
45
 
45
46
  static VALUE rbpod_collection_each(VALUE self) {
46
- struct collection *collection = rbpod_collection_unwrap(self);
47
+ struct collection *collection = TYPED_DATA_PTR(self, struct collection);
47
48
  GList *current = NULL;
48
49
  VALUE item;
49
50
 
50
- if (rb_block_given_p() == TRUE) {
51
- /* If we were supplied a block, enumerate the entire list. */
52
- for (current = collection->list; current != NULL; current = current->next) {
53
- item = Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);
54
- rb_yield(item);
55
- }
56
- return Qnil;
57
- } else {
58
- /* Otherwise return an enumerator from this method to the caller. */
51
+ if (rb_block_given_p() == FALSE)
59
52
  return rb_funcall(self, rb_intern("enum_for"), 1, ID2SYM(rb_intern("each")));
53
+
54
+ /* If we were supplied a block, enumerate the entire list. */
55
+ for (current = collection->list; current != NULL; current = current->next) {
56
+ item = Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);
57
+ rb_yield(item);
60
58
  }
59
+
60
+ return Qnil;
61
61
  }
62
62
 
63
63
  static VALUE rbpod_collection_initialize(VALUE self) {
@@ -74,15 +74,11 @@ static void rbpod_collection_deallocate(void *handle) {
74
74
  return;
75
75
  }
76
76
 
77
- inline VALUE rbpod_collection_wrap(GList *list, VALUE type, gboolean freeable) {
78
- struct collection *collection = ALLOC(struct collection);
79
- collection->list = list;
80
- collection->klass = type;
81
- return Data_Wrap_Struct(cRbPodCollection, NULL, freeable ? rbpod_collection_deallocate : NULL, (void *) collection);
82
- }
83
-
84
77
  static VALUE rbpod_collection_allocate(VALUE self) {
85
- return rbpod_collection_wrap(g_list_alloc(), Qnil, TRUE);
78
+ struct collection *collection = ALLOC(struct collection);
79
+ collection->list = NULL;
80
+ collection->klass = Qnil;
81
+ return Data_Wrap_Struct(cRbPodCollection, NULL, rbpod_collection_deallocate, (void *) collection);
86
82
  }
87
83
 
88
84
  void Init_rbpod_collection(void) {
@@ -95,7 +91,10 @@ void Init_rbpod_collection(void) {
95
91
  rb_define_method(cRbPodCollection, "initialize", rbpod_collection_initialize, 0);
96
92
 
97
93
  rb_define_method(cRbPodCollection, "each", rbpod_collection_each, 0);
98
- rb_define_method(cRbPodCollection, "count", rbpod_collection_count, 0);
94
+
95
+ rb_define_method(cRbPodCollection, "length", rbpod_collection_length, 0);
96
+
97
+ rb_define_alias(cRbPodCollection, "size", "length");
99
98
 
100
99
  rb_define_method(cRbPodCollection, "first", rbpod_collection_first, 0);
101
100
  rb_define_method(cRbPodCollection, "last", rbpod_collection_last, 0);
@@ -7,6 +7,6 @@ extern VALUE cRbPodCollection;
7
7
 
8
8
  void Init_rbpod_collection(void);
9
9
 
10
- inline VALUE rbpod_collection_wrap(GList *list, VALUE type, gboolean freeable);
10
+ inline VALUE rbpod_collection_create(GList *list, VALUE type);
11
11
 
12
12
  #endif /* RBPOD_COLLECTION_H */
data/ext/rbpod/database.c CHANGED
@@ -7,84 +7,72 @@
7
7
  #include "database.h"
8
8
  #include "collection.h"
9
9
 
10
- /*
11
- * Although libgpod has an itdb_new(), itdb_parse() also returns a pointer to a
12
- * newly allocated Itdb_iTunesDB structure. Since overwriting the data pointer from
13
- * Data_Get_Struct() at runtime is dangerous, we use a double-pointer to wrap the
14
- * Itdb_iTunesDB handle, so as not to confuse the Ruby implementation internals.
15
- */
16
-
17
10
  VALUE cRbPodDatabase;
18
11
 
19
- static inline Itdb_iTunesDB *rbpod_database_unwrap(VALUE self) {
20
- Itdb_iTunesDB **database = NULL;
21
- Data_Get_Struct(self, Itdb_iTunesDB *, database);
22
- return *database;
23
- }
24
-
25
12
  static VALUE rbpod_database_write(VALUE self) {
26
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
13
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
27
14
  gboolean success = itdb_write(database, NULL); /* TODO: Improve error handling. */
28
15
  return BooleanValue(success);
29
16
  }
30
17
 
31
18
  static VALUE rbpod_database_is_synchronized(VALUE self) {
32
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
19
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
33
20
  guint32 nontransferred = itdb_tracks_number_nontransferred(database);
34
21
  return BooleanValue(nontransferred == 0);
35
22
  }
36
23
 
37
24
  static VALUE rbpod_database_playlists_get(VALUE self) {
38
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
39
- return rbpod_collection_wrap(database->playlists, cRbPodPlaylist, FALSE);
25
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
26
+ return rbpod_playlist_collection_create(self, database->playlists);
40
27
  }
41
28
 
42
29
  static VALUE rbpod_database_tracks_get(VALUE self) {
43
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
44
- return rbpod_collection_wrap(database->tracks, cRbPodTrack, FALSE);
30
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
31
+ Itdb_Playlist *playlist = itdb_playlist_mpl(database);
32
+ /* Use the master playlist as the parent for the master track list. */
33
+ VALUE parent = Data_Wrap_Struct(cRbPodPlaylist, NULL, NULL, (void *) playlist);
34
+ return rbpod_track_collection_create(parent, database->tracks);
45
35
  }
46
36
 
47
37
  static VALUE rbpod_database_device_get(VALUE self) {
48
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
49
- return rbpod_device_wrap(database->device, FALSE);
38
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
39
+ return rbpod_device_create(database->device);
50
40
  }
51
41
 
52
42
  static VALUE rbpod_database_filename_get(VALUE self) {
53
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
43
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
54
44
  return rb_str_new2(database->filename);
55
45
  }
56
46
 
57
47
  static VALUE rbpod_database_version_get(VALUE self) {
58
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
48
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
59
49
  return INT2NUM(database->version);
60
50
  }
61
51
 
62
52
  static VALUE rbpod_database_id_get(VALUE self) {
63
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
53
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
64
54
  return INT2NUM(database->id);
65
55
  }
66
56
 
67
57
  static VALUE rbpod_database_mountpoint_get(VALUE self) {
68
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
58
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
69
59
  return rb_str_new2(itdb_get_mountpoint(database));
70
60
  }
71
61
 
72
62
  static VALUE rbpod_database_mountpoint_set(VALUE self, VALUE path) {
73
- Itdb_iTunesDB *database = rbpod_database_unwrap(self);
63
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
74
64
  itdb_set_mountpoint(database, StringValueCStr(path));
75
65
  return rbpod_database_mountpoint_get(self);
76
66
  }
77
67
 
78
68
  static void rbpod_database_deallocate(void *handle) {
79
- Itdb_iTunesDB **database = (Itdb_iTunesDB **) handle;
80
- itdb_free(*database);
81
- xfree(handle);
69
+ itdb_free((Itdb_iTunesDB *) handle);
82
70
  return;
83
71
  }
84
72
 
85
73
  static VALUE rbpod_database_create(VALUE self, VALUE device_name, VALUE mount_point, VALUE model_number) {
86
- Itdb_iTunesDB **database = ALLOC(Itdb_iTunesDB *);
87
74
  gchar *_mount_point, *_model_number, *_device_name;
75
+ Itdb_iTunesDB *database = NULL;
88
76
 
89
77
  _device_name = StringValueCStr(device_name);
90
78
  _mount_point = StringValueCStr(mount_point);
@@ -95,55 +83,44 @@ static VALUE rbpod_database_create(VALUE self, VALUE device_name, VALUE mount_po
95
83
  /* Initialize the iPod at this mount point, with this device name and model number. */
96
84
  /* TODO: Improve error handling. */
97
85
  if (itdb_init_ipod(_mount_point, _model_number, _device_name, NULL) == FALSE) {
98
- free(database);
99
- rb_raise(rb_eRuntimeError, "Unable to format this iPod.");
86
+ rb_raise(eRbPodError, "Unable to format this iPod.");
100
87
  return Qfalse;
101
88
  }
102
89
 
103
90
  /* Parse the newly created database. */
104
91
  /* TODO: Improve error handling. */
105
- *database = itdb_parse(_mount_point, NULL);
92
+ database = itdb_parse(_mount_point, NULL);
106
93
 
107
- if (*database == NULL) {
108
- free(database);
109
- rb_raise(rb_eRuntimeError, "Not an iPod mount point.");
94
+ if (database == NULL) {
95
+ rb_raise(eRbPodError, "Not an iPod mount point.");
110
96
  return Qnil;
111
97
  }
112
98
 
113
99
  /* Return an instance of this class using the newly created database. */
114
- return Data_Wrap_Struct(self, NULL, rbpod_database_deallocate, (void *) database);
100
+ return Data_Wrap_Struct(cRbPodDatabase, NULL, rbpod_database_deallocate, (void *) database);
115
101
  }
116
102
 
117
103
  static VALUE rbpod_database_initialize(VALUE self, VALUE mount_point) {
118
- Itdb_iTunesDB **database;
119
-
120
- /* Extract the wrapper from the class itself. */
121
- Data_Get_Struct(self, Itdb_iTunesDB *, database);
104
+ Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
122
105
 
123
106
  /* Try to parse the database from the given mount point. */
124
107
  /* TODO: Improve error handling. */
125
- *database = itdb_parse(StringValueCStr(mount_point), NULL);
108
+ database = itdb_parse(StringValueCStr(mount_point), NULL);
126
109
 
127
110
  /* The given mount point was not an iPod mount point. */
128
- if (*database == NULL) {
129
- rb_raise(rb_eRuntimeError, "Not an iPod mount point.");
111
+ if (database == NULL) {
112
+ rb_raise(eRbPodError, "This is not an iPod mount point.");
130
113
  return Qnil;
131
114
  }
132
115
 
133
- return self;
134
- }
116
+ DATA_PTR(self) = database;
135
117
 
136
- inline VALUE rbpod_database_wrap(Itdb_iTunesDB **database, gboolean freeable) {
137
- return Data_Wrap_Struct(cRbPodDatabase, NULL, freeable ? rbpod_database_deallocate : NULL, (void *) database);
118
+ return self;
138
119
  }
139
120
 
140
121
  static VALUE rbpod_database_allocate(VALUE self) {
141
- Itdb_iTunesDB **database = ALLOC(Itdb_iTunesDB *);
142
-
143
- /* Initialize a new, empty database. */
144
- *database = itdb_new();
145
-
146
- return rbpod_database_wrap(database, TRUE);
122
+ Itdb_iTunesDB *database = itdb_new();
123
+ return Data_Wrap_Struct(cRbPodDatabase, NULL, rbpod_database_deallocate, (void *) database);
147
124
  }
148
125
 
149
126
  void Init_rbpod_database(void) {
data/ext/rbpod/database.h CHANGED
@@ -7,6 +7,4 @@ extern VALUE cRbPodDatabase;
7
7
 
8
8
  void Init_rbpod_database(void);
9
9
 
10
- inline VALUE rbpod_database_wrap(Itdb_iTunesDB **database, gboolean freeable);
11
-
12
10
  #endif /* RBPOD_DATABASE_H */
data/ext/rbpod/device.c CHANGED
@@ -5,63 +5,66 @@
5
5
 
6
6
  VALUE cRbPodDevice;
7
7
 
8
- static inline Itdb_Device *rbpod_device_unwrap(VALUE self) {
9
- Itdb_Device *device = NULL;
10
- Data_Get_Struct(self, Itdb_Device, device);
11
- return device;
8
+ inline VALUE rbpod_device_create(Itdb_Device *device) {
9
+ return Data_Wrap_Struct(cRbPodDevice, NULL, NULL, (void *) device);
12
10
  }
13
11
 
14
12
  static VALUE rbpod_device_has_chapter_image_support(VALUE self) {
15
- Itdb_Device *device = rbpod_device_unwrap(self);
13
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
16
14
  return BooleanValue(itdb_device_supports_chapter_image(device));
17
15
  }
18
16
 
19
17
  static VALUE rbpod_device_has_podcast_support(VALUE self) {
20
- Itdb_Device *device = rbpod_device_unwrap(self);
18
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
21
19
  return BooleanValue(itdb_device_supports_podcast(device));
22
20
  }
23
21
 
24
22
  static VALUE rbpod_device_has_artwork_support(VALUE self) {
25
- Itdb_Device *device = rbpod_device_unwrap(self);
23
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
26
24
  return BooleanValue(itdb_device_supports_artwork(device));
27
25
  }
28
26
 
29
27
  static VALUE rbpod_device_has_video_support(VALUE self) {
30
- Itdb_Device *device = rbpod_device_unwrap(self);
28
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
31
29
  return BooleanValue(itdb_device_supports_video(device));
32
30
  }
33
31
 
34
32
  static VALUE rbpod_device_has_photo_support(VALUE self) {
35
- Itdb_Device *device = rbpod_device_unwrap(self);
33
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
36
34
  return BooleanValue(itdb_device_supports_photo(device));
37
35
  }
38
36
 
39
37
  static VALUE rbpod_device_model_name_get(VALUE self) {
40
- Itdb_Device *device = rbpod_device_unwrap(self);
41
- Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
38
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
39
+ const Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
42
40
  return rb_str_new2(itdb_info_get_ipod_model_name_string(info->ipod_model));
43
41
  }
44
42
 
45
43
  static VALUE rbpod_device_model_number_get(VALUE self) {
46
- Itdb_Device *device = rbpod_device_unwrap(self);
47
- Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
44
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
45
+ const Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
48
46
  return rb_str_new2(info->model_number);
49
47
  }
50
48
 
51
49
  static VALUE rbpod_device_generation_get(VALUE self) {
52
- Itdb_Device *device = rbpod_device_unwrap(self);
50
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
53
51
  const Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
54
52
  return rb_str_new2(itdb_info_get_ipod_generation_string(info->ipod_generation));
55
53
  }
56
54
 
57
55
  static VALUE rbpod_device_capacity_get(VALUE self) {
58
- Itdb_Device *device = rbpod_device_unwrap(self);
56
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
59
57
  const Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
60
58
  return DBL2NUM(info->capacity);
61
59
  }
62
60
 
61
+ static VALUE rbpod_device_uuid_get(VALUE self) {
62
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
63
+ return rb_str_new2(itdb_device_get_uuid(device));
64
+ }
65
+
63
66
  static VALUE rbpod_device_sysinfo_get(VALUE self, VALUE key) {
64
- Itdb_Device *device = rbpod_device_unwrap(self);
67
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
65
68
  gchar *value = NULL;
66
69
  VALUE result;
67
70
 
@@ -74,7 +77,7 @@ static VALUE rbpod_device_sysinfo_get(VALUE self, VALUE key) {
74
77
  }
75
78
 
76
79
  static VALUE rbpod_device_sysinfo_set(VALUE self, VALUE key, VALUE value) {
77
- Itdb_Device *device = rbpod_device_unwrap(self);
80
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
78
81
  gchar *_value, *_key;
79
82
 
80
83
  _key = StringValueCStr(key);
@@ -82,17 +85,17 @@ static VALUE rbpod_device_sysinfo_set(VALUE self, VALUE key, VALUE value) {
82
85
 
83
86
  itdb_device_set_sysinfo(device, _key, _value);
84
87
 
85
- return rbpod_device_sysinfo_get(self, _key);
88
+ return rbpod_device_sysinfo_get(self, key);
86
89
  }
87
90
 
88
91
  static VALUE rbpod_device_sysinfo_write(VALUE self) {
89
- Itdb_Device *device = rbpod_device_unwrap(self);
92
+ Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
90
93
  /* TODO: Improve error handling. */
91
94
  return BooleanValue(itdb_device_write_sysinfo(device, NULL));
92
95
  }
93
96
 
94
97
  static VALUE rbpod_device_initialize(VALUE self) {
95
- /* Private. */
98
+ /* Private method, no setup required yet. */
96
99
  return self;
97
100
  }
98
101
 
@@ -100,12 +103,8 @@ static void rbpod_device_deallocate(void *handle) {
100
103
  itdb_device_free((Itdb_Device *) handle);
101
104
  }
102
105
 
103
- inline VALUE rbpod_device_wrap(Itdb_Device *device, gboolean freeable) {
104
- return Data_Wrap_Struct(cRbPodDevice, NULL, freeable ? rbpod_device_deallocate : NULL, (void *) device);
105
- }
106
-
107
106
  static VALUE rbpod_device_allocate(VALUE self) {
108
- return rbpod_device_wrap(itdb_device_new(), TRUE);
107
+ return Data_Wrap_Struct(cRbPodDevice, NULL, rbpod_device_deallocate, (void *) itdb_device_new());
109
108
  }
110
109
 
111
110
  void Init_rbpod_device(void) {
@@ -120,6 +119,7 @@ void Init_rbpod_device(void) {
120
119
  rb_define_method(cRbPodDevice, "[]=", rbpod_device_sysinfo_set, 2);
121
120
  rb_define_method(cRbPodDevice, "save!", rbpod_device_sysinfo_write, 0);
122
121
 
122
+ rb_define_method(cRbPodDevice, "uuid", rbpod_device_uuid_get, 0);
123
123
  rb_define_method(cRbPodDevice, "capacity", rbpod_device_capacity_get, 0);
124
124
  rb_define_method(cRbPodDevice, "generation", rbpod_device_generation_get, 0);
125
125
  rb_define_method(cRbPodDevice, "model_name", rbpod_device_model_name_get, 0);
data/ext/rbpod/device.h CHANGED
@@ -7,6 +7,6 @@ extern VALUE cRbPodDevice;
7
7
 
8
8
  void Init_rbpod_device(void);
9
9
 
10
- inline VALUE rbpod_device_wrap(Itdb_Device *device, gboolean freeable);
10
+ inline VALUE rbpod_device_create(Itdb_Device *device);
11
11
 
12
12
  #endif /* RBPOD_DEVICE_H */
data/ext/rbpod/playlist.c CHANGED
@@ -3,51 +3,66 @@
3
3
  #include "rbpod.h"
4
4
  #include "track.h"
5
5
  #include "playlist.h"
6
+ #include "collection.h"
6
7
 
7
8
  VALUE cRbPodPlaylist;
9
+ VALUE mRbPodPlaylistCollection;
8
10
 
9
- static inline Itdb_Playlist *rbpod_playlist_unwrap(VALUE self) {
10
- Itdb_Playlist *playlist = NULL;
11
- Data_Get_Struct(self, Itdb_Playlist, playlist);
12
- return playlist;
11
+ inline VALUE rbpod_playlist_collection_create(VALUE parent, GList *items) {
12
+ VALUE collection = rbpod_collection_create(items, cRbPodPlaylist);
13
+ rb_extend_object(collection, mRbPodPlaylistCollection);
14
+ rb_iv_set(collection, "@parent", parent);
15
+ return collection;
13
16
  }
14
17
 
15
18
  static VALUE rbpod_playlist_is_podcast(VALUE self) {
16
- Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
19
+ Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
17
20
  return BooleanValue(itdb_playlist_is_podcasts(playlist));
18
21
  }
19
22
 
20
23
  static VALUE rbpod_playlist_is_master(VALUE self) {
21
- Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
24
+ Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
22
25
  return BooleanValue(itdb_playlist_is_mpl(playlist));
23
26
  }
24
27
 
25
28
  static VALUE rbpod_playlist_is_smart(VALUE self) {
26
- Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
29
+ Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
27
30
  return BooleanValue(playlist->is_spl);
28
31
  }
29
32
 
33
+ static VALUE rbpod_playlist_timestamp_get(VALUE self) {
34
+ Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
35
+ return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2NUM(playlist->timestamp));
36
+ }
37
+
38
+ static VALUE rbpod_playlist_shuffle(VALUE self) {
39
+ Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
40
+ itdb_playlist_randomize(playlist);
41
+ return Qnil;
42
+ }
43
+
30
44
  static VALUE rbpod_playlist_tracks_get(VALUE self) {
31
- Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
32
- return rbpod_collection_wrap(playlist->members, cRbPodTrack, FALSE);
45
+ Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
46
+ return rbpod_track_collection_create(self, playlist->members);
33
47
  }
34
48
 
35
49
  static VALUE rbpod_playlist_length_get(VALUE self) {
36
- Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
37
- return INT2NUM(playlist->num);
50
+ Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
51
+ return INT2NUM(itdb_playlist_tracks_number(playlist));
38
52
  }
39
53
 
40
54
  static VALUE rbpod_playlist_name_get(VALUE self) {
41
- Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
55
+ Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
42
56
  return rb_str_new2(playlist->name);
43
57
  }
44
58
 
45
59
  static VALUE rbpod_playlist_id_get(VALUE self) {
46
- Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
47
- return INT2FIX(playlist->id);
60
+ Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
61
+ return INT2NUM(playlist->id);
48
62
  }
49
63
 
50
64
  static VALUE rbpod_playlist_initialize(VALUE self) {
65
+ /* Nothing to intiialize, yet. */
51
66
  return self;
52
67
  }
53
68
 
@@ -55,13 +70,9 @@ static void rbpod_playlist_deallocate(void *handle) {
55
70
  itdb_playlist_free((Itdb_Playlist *) handle);
56
71
  }
57
72
 
58
- inline VALUE rbpod_playlist_wrap(Itdb_Playlist *playlist, gboolean freeable) {
59
- return Data_Wrap_Struct(cRbPodPlaylist, NULL, freeable ? rbpod_playlist_deallocate : NULL, (void *) playlist);
60
- }
61
-
62
73
  static VALUE rbpod_playlist_allocate(VALUE self) {
63
74
  Itdb_Playlist *playlist = itdb_playlist_new("Untitled Playlist", FALSE);
64
- return rbpod_playlist_wrap(playlist, TRUE);
75
+ return Data_Wrap_Struct(cRbPodPlaylist, NULL, rbpod_playlist_deallocate, (void *) playlist);
65
76
  }
66
77
 
67
78
  void Init_rbpod_playlist(void) {
@@ -75,11 +86,15 @@ void Init_rbpod_playlist(void) {
75
86
  rb_define_method(cRbPodPlaylist, "name", rbpod_playlist_name_get, 0);
76
87
  rb_define_method(cRbPodPlaylist, "length", rbpod_playlist_length_get, 0);
77
88
  rb_define_method(cRbPodPlaylist, "tracks", rbpod_playlist_tracks_get, 0);
89
+ rb_define_method(cRbPodPlaylist, "shuffle!", rbpod_playlist_shuffle, 0);
90
+ rb_define_method(cRbPodPlaylist, "created_on", rbpod_playlist_timestamp_get, 0);
78
91
 
79
92
  rb_define_method(cRbPodPlaylist, "smart_playlist?", rbpod_playlist_is_smart, 0);
80
93
  rb_define_method(cRbPodPlaylist, "master_playlist?", rbpod_playlist_is_master, 0);
81
94
  rb_define_method(cRbPodPlaylist, "podcast_playlist?", rbpod_playlist_is_podcast, 0);
82
95
 
96
+ mRbPodPlaylistCollection = rb_define_module_under(cRbPodPlaylist, "Collection");
97
+
83
98
  return;
84
99
  }
85
100
 
data/ext/rbpod/playlist.h CHANGED
@@ -4,9 +4,10 @@
4
4
  #define RBPOD_PLAYLIST_H
5
5
 
6
6
  extern VALUE cRbPodPlaylist;
7
+ extern VALUE mRbPodPlaylistCollection;
7
8
 
8
9
  void Init_rbpod_playlist(void);
9
10
 
10
- inline VALUE rbpod_playlist_wrap(Itdb_Playlist *playlist, gboolean freeable);
11
+ inline VALUE rbpod_playlist_collection_create(VALUE parent, GList *items);
11
12
 
12
13
  #endif /* RBPOD_PLAYLIST_H */
data/ext/rbpod/rbpod.c CHANGED
@@ -8,11 +8,15 @@
8
8
  #include "collection.h"
9
9
 
10
10
  VALUE mRbPod;
11
+ VALUE eRbPodError;
11
12
 
12
13
  void Init_rbpod(void) {
13
14
  /* Set up the top-level RbPod module. */
14
15
  mRbPod = rb_define_module("RbPod");
15
16
 
17
+ /* Subclass RuntimeError for ourselves. */
18
+ eRbPodError = rb_define_class_under(mRbPod, "Error", rb_eRuntimeError);
19
+
16
20
  /* Set up the RbPod::Database class. */
17
21
  Init_rbpod_database();
18
22
 
data/ext/rbpod/rbpod.h CHANGED
@@ -8,6 +8,9 @@
8
8
 
9
9
  #define BooleanValue(value) (value) ? Qtrue : Qfalse
10
10
 
11
+ #define TYPED_DATA_PTR(self, type) ((type *) DATA_PTR(self))
12
+
11
13
  extern VALUE mRbPod;
14
+ extern VALUE eRbPodError;
12
15
 
13
16
  #endif /* RBPOD_H */
data/ext/rbpod/track.c CHANGED
@@ -2,47 +2,50 @@
2
2
 
3
3
  #include "rbpod.h"
4
4
  #include "track.h"
5
+ #include "collection.h"
5
6
 
6
7
  VALUE cRbPodTrack;
8
+ VALUE mRbPodTrackCollection;
7
9
 
8
- static inline Itdb_Track *rbpod_track_unwrap(VALUE self) {
9
- Itdb_Track *track = NULL;
10
- Data_Get_Struct(self, Itdb_Track, track);
11
- return track;
10
+ inline VALUE rbpod_track_collection_create(VALUE parent, GList *items) {
11
+ VALUE collection = rbpod_collection_create(items, cRbPodTrack);
12
+ rb_extend_object(collection, mRbPodTrackCollection);
13
+ rb_iv_set(collection, "@parent", parent);
14
+ return collection;
12
15
  }
13
16
 
14
17
  static VALUE rbpod_track_is_transferred(VALUE self) {
15
- Itdb_Track *track = rbpod_track_unwrap(self);
18
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
16
19
  return BooleanValue(track->transferred);
17
20
  }
18
21
 
19
22
  static VALUE rbpod_track_ipod_path_get(VALUE self) {
20
- Itdb_Track *track = rbpod_track_unwrap(self);
23
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
21
24
  return rb_str_new2(track->ipod_path);
22
25
  }
23
26
 
24
27
  static VALUE rbpod_track_file_type_get(VALUE self) {
25
- Itdb_Track *track = rbpod_track_unwrap(self);
28
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
26
29
  return rb_str_new2(track->filetype);
27
30
  }
28
31
 
29
32
  static VALUE rbpod_track_artist_get(VALUE self) {
30
- Itdb_Track *track = rbpod_track_unwrap(self);
33
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
31
34
  return rb_str_new2(track->artist);
32
35
  }
33
36
 
34
37
  static VALUE rbpod_track_album_get(VALUE self) {
35
- Itdb_Track *track = rbpod_track_unwrap(self);
38
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
36
39
  return rb_str_new2(track->album);
37
40
  }
38
41
 
39
42
  static VALUE rbpod_track_title_get(VALUE self) {
40
- Itdb_Track *track = rbpod_track_unwrap(self);
43
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
41
44
  return rb_str_new2(track->title);
42
45
  }
43
46
 
44
47
  static VALUE rbpod_track_id_get(VALUE self) {
45
- Itdb_Track *track = rbpod_track_unwrap(self);
48
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
46
49
  return rb_str_new2(track->filetype);
47
50
  }
48
51
 
@@ -55,12 +58,9 @@ static void rbpod_track_deallocate(void *handle) {
55
58
  return;
56
59
  }
57
60
 
58
- inline VALUE rbpod_track_wrap(Itdb_Track *track, gboolean freeable) {
59
- return Data_Wrap_Struct(cRbPodTrack, NULL, freeable ? rbpod_track_deallocate : NULL, (void *) track);
60
- }
61
-
62
61
  static VALUE rbpod_track_allocate(VALUE self) {
63
- return rbpod_track_wrap(itdb_track_new(), TRUE);
62
+ Itdb_Track *track = itdb_track_new();
63
+ return Data_Wrap_Struct(cRbPodTrack, NULL, rbpod_track_deallocate, (void *) track);
64
64
  }
65
65
 
66
66
  void Init_rbpod_track(void) {
@@ -79,6 +79,8 @@ void Init_rbpod_track(void) {
79
79
 
80
80
  rb_define_method(cRbPodTrack, "transferred?", rbpod_track_is_transferred, 0);
81
81
 
82
+ mRbPodTrackCollection = rb_define_module_under(cRbPodTrack, "Collection");
83
+
82
84
  return;
83
85
  }
84
86
 
data/ext/rbpod/track.h CHANGED
@@ -4,9 +4,10 @@
4
4
  #define RBPOD_TRACK_H
5
5
 
6
6
  extern VALUE cRbPodTrack;
7
+ extern VALUE mRbPodTrackCollection;
7
8
 
8
9
  void Init_rbpod_track(void);
9
10
 
10
- inline VALUE rbpod_track_wrap(Itdb_Track *track, gboolean freeable);
11
+ inline VALUE rbpod_track_collection_create(VALUE parent, GList *items);
11
12
 
12
13
  #endif /* RBPOD_TRACK_H */
data/lib/rbpod/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RbPod
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/rbpod.gemspec CHANGED
@@ -23,6 +23,9 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ['lib']
24
24
 
25
25
  spec.add_development_dependency 'bundler', '~> 1.3'
26
+ spec.add_development_dependency 'rspec', '~> 2.14'
27
+
28
+ spec.add_development_dependency 'rake-compiler', '~> 0.8'
26
29
  spec.add_development_dependency 'rake'
27
30
 
28
31
  spec.add_dependency 'trollop', '~> 2.0'
@@ -0,0 +1,7 @@
1
+ require 'rspec'
2
+ require 'rbpod'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ config.formatter = 'documentation'
7
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbpod
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-25 00:00:00.000000000 Z
12
+ date: 2013-10-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -27,6 +27,38 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2.14'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.14'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake-compiler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '0.8'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.8'
30
62
  - !ruby/object:Gem::Dependency
31
63
  name: rake
32
64
  requirement: !ruby/object:Gem::Requirement
@@ -90,6 +122,7 @@ files:
90
122
  - lib/rbpod.rb
91
123
  - lib/rbpod/version.rb
92
124
  - rbpod.gemspec
125
+ - spec/spec_helper.rb
93
126
  homepage: https://github.com/jmkeyes/rbpod
94
127
  licenses:
95
128
  - MIT
@@ -103,12 +136,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
136
  - - ! '>='
104
137
  - !ruby/object:Gem::Version
105
138
  version: '0'
139
+ segments:
140
+ - 0
141
+ hash: 658402081
106
142
  required_rubygems_version: !ruby/object:Gem::Requirement
107
143
  none: false
108
144
  requirements:
109
145
  - - ! '>='
110
146
  - !ruby/object:Gem::Version
111
147
  version: '0'
148
+ segments:
149
+ - 0
150
+ hash: 658402081
112
151
  requirements:
113
152
  - libgpod-1.0
114
153
  rubyforge_project:
@@ -116,4 +155,5 @@ rubygems_version: 1.8.23
116
155
  signing_key:
117
156
  specification_version: 3
118
157
  summary: Ruby bindings to the libgpod library.
119
- test_files: []
158
+ test_files:
159
+ - spec/spec_helper.rb