rbpod 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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