angularjs-rails-resource 0.2.5 → 1.0.0.pre.1

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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * A resource factory inspired by $resource from AngularJS
3
- * @version v0.2.5 - 2013-11-24
3
+ * @version v1.0.0-pre1 - 2013-10-06
4
4
  * @link https://github.com/FineLinePrototyping/angularjs-rails-resource.git
5
5
  * @author
6
6
  */
@@ -120,7 +120,7 @@
120
120
  return function (url) {
121
121
  var expression;
122
122
 
123
- if (angular.isFunction(url)) {
123
+ if (angular.isFunction(url) || angular.isUndefined(url)) {
124
124
  return url;
125
125
  }
126
126
 
@@ -352,7 +352,7 @@
352
352
  * Specify a custom serializer to use for an attribute.
353
353
  *
354
354
  * @param attributeName {string} The name of the attribute
355
- * @param serializer {string | constructor} A reference to the custom serializer to use for the attribute.
355
+ * @param serializer {string | function} A reference to the custom serializer to use for the attribute.
356
356
  * @returns {Serializer} this for chaining support
357
357
  */
358
358
  Serializer.prototype.serializeWith = function (attributeName, serializer) {
@@ -408,17 +408,8 @@
408
408
  Serializer.prototype.getSerializedAttributeName = function (attributeName) {
409
409
  var mappedName = this.serializeMappings[attributeName] || attributeName;
410
410
 
411
- var mappedNameExcluded = this.isExcludedFromSerialization(mappedName),
412
- attributeNameExcluded = this.isExcludedFromSerialization(attributeName);
413
-
414
- if(this.options.excludeByDefault) {
415
- if(mappedNameExcluded && attributeNameExcluded) {
416
- return undefined;
417
- }
418
- } else {
419
- if (mappedNameExcluded || attributeNameExcluded) {
420
- return undefined;
421
- }
411
+ if (this.isExcludedFromSerialization(attributeName) || this.isExcludedFromSerialization(mappedName)) {
412
+ return undefined;
422
413
  }
423
414
 
424
415
  return this.underscore(mappedName);
@@ -483,9 +474,9 @@
483
474
 
484
475
  // custom serializer takes precedence over resource serializer
485
476
  if (serializer) {
486
- return RailsResourceInjector.createService(serializer);
477
+ return RailsResourceInjector.createService(serializer)
487
478
  } else if (resource) {
488
- return resource.serializer;
479
+ return resource.config.serializer;
489
480
  }
490
481
 
491
482
  return undefined;
@@ -597,7 +588,7 @@
597
588
  result = {};
598
589
 
599
590
  if (Resource) {
600
- result = new Resource();
591
+ result = new Resource.config.resourceConstructor();
601
592
  }
602
593
 
603
594
  angular.forEach(data, function (value, key) {
@@ -687,7 +678,7 @@
687
678
  angular.module('rails').factory('railsRootWrappingTransformer', function () {
688
679
  return function (data, resource) {
689
680
  var result = {};
690
- result[angular.isArray(data) ? resource.rootPluralName : resource.rootName] = data;
681
+ result[angular.isArray(data) ? resource.config.pluralName : resource.config.name] = data;
691
682
  return result;
692
683
  };
693
684
  });
@@ -701,10 +692,10 @@
701
692
  }
702
693
 
703
694
  return promise.then(function (response) {
704
- if (response.data && response.data.hasOwnProperty(resource.rootName)) {
705
- response.data = response.data[resource.rootName];
706
- } else if (response.data && response.data.hasOwnProperty(resource.rootPluralName)) {
707
- response.data = response.data[resource.rootPluralName];
695
+ if (response.data && response.data.hasOwnProperty(resource.config.name)) {
696
+ response.data = response.data[resource.config.name];
697
+ } else if (response.data && response.data.hasOwnProperty(resource.config.pluralName)) {
698
+ response.data = response.data[resource.config.pluralName];
708
699
  }
709
700
 
710
701
  return response;
@@ -712,16 +703,16 @@
712
703
  };
713
704
  });
714
705
 
715
- angular.module('rails').provider('railsResourceFactory', function () {
706
+ angular.module('rails').provider('RailsResource', function () {
716
707
  var defaultOptions = {
717
- enableRootWrapping: true,
708
+ rootWrapping: true,
718
709
  updateMethod: 'put',
719
710
  httpConfig: {},
720
711
  defaultParams: undefined
721
712
  };
722
713
 
723
- this.enableRootWrapping = function (value) {
724
- defaultOptions.enableRootWrapping = value;
714
+ this.rootWrapping = function (value) {
715
+ defaultOptions.rootWrapping = value;
725
716
  return this;
726
717
  };
727
718
 
@@ -743,11 +734,6 @@
743
734
  this.$get = ['$http', '$q', 'railsUrlBuilder', 'railsSerializer', 'railsRootWrappingTransformer', 'railsRootWrappingInterceptor', 'RailsResourceInjector',
744
735
  function ($http, $q, railsUrlBuilder, railsSerializer, railsRootWrappingTransformer, railsRootWrappingInterceptor, RailsResourceInjector) {
745
736
 
746
- function railsResourceFactory(config) {
747
- var transformers = config.requestTransformers,
748
- interceptors = config.responseInterceptors,
749
- afterInterceptors = config.afterResponseInterceptors;
750
-
751
737
  function appendPath(url, path) {
752
738
  if (path) {
753
739
  if (path[0] !== '/') {
@@ -760,43 +746,100 @@
760
746
  return url;
761
747
  }
762
748
 
749
+ function forEachDependency(list, callback) {
750
+ var dependency;
751
+
752
+ for (var i = 0, len = list.length; i < len; i++) {
753
+ dependency = list[i];
754
+
755
+ if (angular.isString(dependency)) {
756
+ dependency = list[i] = RailsResourceInjector.getDependency(dependency);
757
+ }
758
+
759
+ callback(dependency);
760
+ }
761
+ }
762
+
763
763
  function RailsResource(value) {
764
764
  var instance = this;
765
765
  if (value) {
766
- var immediatePromise = function(data) {
766
+ var immediatePromise = function (data) {
767
767
  return {
768
768
  resource: RailsResource,
769
769
  context: instance,
770
770
  response: data,
771
- then: function(callback) {
771
+ then: function (callback) {
772
772
  this.response = callback(this.response, this.resource, this.context);
773
773
  return immediatePromise(this.response);
774
774
  }
775
775
  }
776
776
  };
777
777
 
778
- var data = RailsResource.callInterceptors(immediatePromise({data: value}), this).response.data;
778
+ var data = this.constructor.callInterceptors(immediatePromise({data: value}), this).response.data;
779
779
  angular.extend(this, data);
780
780
  }
781
781
  }
782
782
 
783
- RailsResource.setUrl = function(url) {
784
- RailsResource.url = railsUrlBuilder(url);
783
+ RailsResource.extend = function (child) {
784
+ // Extend logic copied from CoffeeScript generated code
785
+ var __hasProp = {}.hasOwnProperty, parent = this;
786
+ for (var key in parent) {
787
+ if (__hasProp.call(parent, key)) child[key] = parent[key];
788
+ }
789
+
790
+ function ctor() {
791
+ this.constructor = child;
792
+ }
793
+
794
+ ctor.prototype = parent.prototype;
795
+ child.prototype = new ctor();
796
+ child.__super__ = parent.prototype;
797
+ return child;
785
798
  };
786
- RailsResource.setUrl(config.url);
787
799
 
788
- RailsResource.enableRootWrapping = config.wrapData === undefined ? defaultOptions.enableRootWrapping : config.wrapData; // using undefined check because config.wrapData || true would be true when config.wrapData === false
789
- RailsResource.httpConfig = config.httpConfig || defaultOptions.httpConfig;
790
- RailsResource.httpConfig.headers = angular.extend({'Accept': 'application/json', 'Content-Type': 'application/json'}, RailsResource.httpConfig.headers || {});
791
- RailsResource.defaultParams = config.defaultParams || defaultOptions.defaultParams;
792
- RailsResource.updateMethod = (config.updateMethod || defaultOptions.updateMethod).toLowerCase();
800
+ // allow calling configure multiple times to set configuration options and override values from inherited resources
801
+ RailsResource.configure = function (cfg) {
802
+ cfg = cfg || {};
803
+
804
+ if (this.config) {
805
+ cfg = angular.extend({}, this.config, cfg);
806
+ }
807
+
808
+ this.config = {};
809
+ this.config.url = cfg.url;
810
+ this.config.rootWrapping = cfg.rootWrapping === undefined ? defaultOptions.rootWrapping : cfg.rootWrapping; // using undefined check because config.rootWrapping || true would be true when config.rootWrapping === false
811
+ this.config.httpConfig = cfg.httpConfig || defaultOptions.httpConfig;
812
+ this.config.httpConfig.headers = angular.extend({'Accept': 'application/json', 'Content-Type': 'application/json'}, this.config.httpConfig.headers || {});
813
+ this.config.defaultParams = cfg.defaultParams || defaultOptions.defaultParams;
814
+ this.config.updateMethod = (cfg.updateMethod || defaultOptions.updateMethod).toLowerCase();
815
+
816
+ this.config.requestTransformers = cfg.requestTransformers ? cfg.requestTransformers.slice(0) : [];
817
+ this.config.responseInterceptors = cfg.responseInterceptors ? cfg.responseInterceptors.slice(0) : [];
818
+ this.config.afterResponseInterceptors = cfg.afterResponseInterceptors ? cfg.afterResponseInterceptors.slice(0) : [];
819
+
820
+ // strings and functions are not considered objects by angular.isObject()
821
+ if (angular.isObject(cfg.serializer)) {
822
+ this.config.serializer = cfg.serializer;
823
+ } else {
824
+ this.config.serializer = RailsResourceInjector.createService(cfg.serializer || railsSerializer());
825
+ }
826
+
827
+ this.config.name = this.config.serializer.underscore(cfg.name);
828
+ this.config.pluralName = this.config.serializer.underscore(cfg.pluralName || this.config.serializer.pluralize(this.config.name));
829
+
830
+ this.config.urlBuilder = railsUrlBuilder(this.config.url);
831
+ this.config.resourceConstructor = this;
832
+ };
793
833
 
794
- RailsResource.requestTransformers = [];
795
- RailsResource.responseInterceptors = [];
796
- RailsResource.afterResponseInterceptors = [];
797
- RailsResource.serializer = RailsResourceInjector.createService(config.serializer || railsSerializer());
798
- RailsResource.rootName = RailsResource.serializer.underscore(config.name);
799
- RailsResource.rootPluralName = RailsResource.serializer.underscore(config.pluralName || RailsResource.serializer.pluralize(config.name));
834
+ RailsResource.configure({});
835
+
836
+ RailsResource.setUrl = function (url) {
837
+ this.configure({url: url});
838
+ };
839
+
840
+ RailsResource.buildUrl = function (context) {
841
+ return this.config.urlBuilder(context);
842
+ };
800
843
 
801
844
  /**
802
845
  * Add a callback to run on response and construction.
@@ -804,11 +847,11 @@
804
847
  * constructor is the resource class calling the function,
805
848
  * context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
806
849
  */
807
- RailsResource.beforeResponse = function(fn) {
850
+ RailsResource.beforeResponse = function (fn) {
808
851
  fn = RailsResourceInjector.getDependency(fn);
809
- RailsResource.responseInterceptors.push(function(promise) {
810
- return promise.then(function(response) {
811
- fn(response.data, promise.resource, promise.context);
852
+ this.config.responseInterceptors.push(function (promise) {
853
+ return promise.then(function (response) {
854
+ fn(response.data, promise.resource.config.resourceConstructor, promise.context);
812
855
  return response;
813
856
  });
814
857
  });
@@ -818,11 +861,11 @@
818
861
  * Add a callback to run after response has been processed. These callbacks are not called on object construction.
819
862
  * @param fn(response data, constructor) - response data is either the resource instance returned or an array of resource instances and constructor is the resource class calling the function
820
863
  */
821
- RailsResource.afterResponse = function(fn) {
864
+ RailsResource.afterResponse = function (fn) {
822
865
  fn = RailsResourceInjector.getDependency(fn);
823
- RailsResource.afterResponseInterceptors.push(function(promise) {
824
- return promise.then(function(response) {
825
- fn(response, promise.resource);
866
+ this.config.afterResponseInterceptors.push(function (promise) {
867
+ return promise.then(function (response) {
868
+ fn(response, promise.resource.config.resourceConstructor);
826
869
  return response;
827
870
  });
828
871
  });
@@ -832,38 +875,24 @@
832
875
  * Adds a function to run after serializing the data to send to the server, but before root-wrapping it.
833
876
  * @param fn (data, constructor) - data object is the serialized resource instance, and constructor the resource class calling the function
834
877
  */
835
- RailsResource.beforeRequest = function(fn) {
878
+ RailsResource.beforeRequest = function (fn) {
836
879
  fn = RailsResourceInjector.getDependency(fn);
837
- RailsResource.requestTransformers.push(function(data, resource) {
838
- return fn(data, resource) || data;
880
+ this.config.requestTransformers.push(function (data, resource) {
881
+ return fn(data, resource.config.resourceConstructor) || data;
839
882
  });
840
883
  };
841
884
 
842
- // copied from $HttpProvider to support interceptors being dependency names or anonymous factory functions
843
- angular.forEach(interceptors, function (interceptor) {
844
- RailsResource.responseInterceptors.push(RailsResourceInjector.getDependency(interceptor));
845
- });
846
-
847
- angular.forEach(afterInterceptors, function (interceptor) {
848
- RailsResource.afterResponseInterceptors.push(RailsResourceInjector.getDependency(interceptor));
849
- });
850
-
851
- angular.forEach(transformers, function (transformer) {
852
- RailsResource.requestTransformers.push(RailsResourceInjector.getDependency(transformer));
853
- });
854
-
855
885
  // transform data for request:
856
886
  RailsResource.transformData = function (data) {
857
- data = RailsResource.serializer.serialize(data);
887
+ var config = this.config;
888
+ data = config.serializer.serialize(data);
858
889
 
859
- // data is now serialized. call request transformers including beforeRequest
860
- angular.forEach(RailsResource.requestTransformers, function (transformer) {
861
- data = transformer(data, RailsResource);
890
+ forEachDependency(this.config.requestTransformers, function (transformer) {
891
+ data = transformer(data, config.resourceConstructor);
862
892
  });
863
893
 
864
-
865
- if (RailsResource.enableRootWrapping) {
866
- data = railsRootWrappingTransformer(data, RailsResource);
894
+ if (config.rootWrapping) {
895
+ data = railsRootWrappingTransformer(data, config.resourceConstructor);
867
896
  }
868
897
 
869
898
  return data;
@@ -871,25 +900,27 @@
871
900
 
872
901
  // transform data on response:
873
902
  RailsResource.callInterceptors = function (promise, context) {
903
+ var config = this.config;
904
+
874
905
  promise = promise.then(function (response) {
875
906
  // store off the data in case something (like our root unwrapping) assigns data as a new object
876
907
  response.originalData = response.data;
877
908
  return response;
878
909
  });
879
910
 
880
- if (RailsResource.enableRootWrapping) {
881
- promise.resource = RailsResource;
911
+ if (config.rootWrapping) {
912
+ promise.resource = config.resourceConstructor;
882
913
  promise = railsRootWrappingInterceptor(promise);
883
914
  }
884
915
 
885
916
  promise.then(function (response) {
886
- response.data = RailsResource.serializer.deserialize(response.data, RailsResource);
917
+ response.data = config.serializer.deserialize(response.data, config.resourceConstructor);
887
918
  return response;
888
919
  });
889
920
 
890
921
  // data is now deserialized. call response interceptors including beforeResponse
891
- angular.forEach(RailsResource.responseInterceptors, function (interceptor) {
892
- promise.resource = RailsResource;
922
+ forEachDependency(config.responseInterceptors, function (interceptor) {
923
+ promise.resource = config.resourceConstructor;
893
924
  promise.context = context;
894
925
  promise = interceptor(promise);
895
926
  });
@@ -899,9 +930,10 @@
899
930
 
900
931
  // transform data after response has been converted to a resource instance:
901
932
  RailsResource.callAfterInterceptors = function (promise) {
933
+ var config = this.config;
902
934
  // data is now deserialized. call response interceptors including afterResponse
903
- angular.forEach(RailsResource.afterResponseInterceptors, function (interceptor) {
904
- promise.resource = RailsResource;
935
+ forEachDependency(config.afterResponseInterceptors, function (interceptor) {
936
+ promise.resource = config.resourceConstructor;
905
937
  promise = interceptor(promise);
906
938
  });
907
939
 
@@ -909,18 +941,18 @@
909
941
  };
910
942
 
911
943
  RailsResource.processResponse = function (promise) {
912
- promise = RailsResource.callInterceptors(promise).then(function (response) {
944
+ promise = this.callInterceptors(promise).then(function (response) {
913
945
  return response.data;
914
946
  });
915
947
 
916
- return RailsResource.callAfterInterceptors(promise);
948
+ return this.callAfterInterceptors(promise);
917
949
  };
918
950
 
919
951
  RailsResource.getParameters = function (queryParams) {
920
952
  var params;
921
953
 
922
- if (RailsResource.defaultParams) {
923
- params = RailsResource.defaultParams;
954
+ if (this.config.defaultParams) {
955
+ params = this.config.defaultParams;
924
956
  }
925
957
 
926
958
  if (angular.isObject(queryParams)) {
@@ -931,13 +963,13 @@
931
963
  };
932
964
 
933
965
  RailsResource.getHttpConfig = function (queryParams) {
934
- var params = RailsResource.getParameters(queryParams);
966
+ var params = this.getParameters(queryParams);
935
967
 
936
968
  if (params) {
937
- return angular.extend({params: params}, RailsResource.httpConfig);
969
+ return angular.extend({params: params}, this.config.httpConfig);
938
970
  }
939
971
 
940
- return angular.copy(RailsResource.httpConfig);
972
+ return angular.copy(this.config.httpConfig);
941
973
  };
942
974
 
943
975
  /**
@@ -960,19 +992,19 @@
960
992
  context = {id: context};
961
993
  }
962
994
 
963
- return appendPath(RailsResource.url(context || {}), path);
995
+ return appendPath(this.buildUrl(context || {}), path);
964
996
  };
965
997
 
966
998
  RailsResource.$get = function (url, queryParams) {
967
- return RailsResource.processResponse($http.get(url, RailsResource.getHttpConfig(queryParams)));
999
+ return this.processResponse($http.get(url, this.getHttpConfig(queryParams)));
968
1000
  };
969
1001
 
970
1002
  RailsResource.query = function (queryParams, context) {
971
- return RailsResource.$get(RailsResource.resourceUrl(context), queryParams);
1003
+ return this.$get(this.resourceUrl(context), queryParams);
972
1004
  };
973
1005
 
974
1006
  RailsResource.get = function (context, queryParams) {
975
- return RailsResource.$get(RailsResource.resourceUrl(context), queryParams);
1007
+ return this.$get(this.resourceUrl(context), queryParams);
976
1008
  };
977
1009
 
978
1010
  /**
@@ -981,12 +1013,12 @@
981
1013
  * @param path {string} (optional) An additional path to append to the URL
982
1014
  * @returns {string} The URL for the resource
983
1015
  */
984
- RailsResource.prototype.$url = function(path) {
985
- return appendPath(RailsResource.resourceUrl(this), path);
1016
+ RailsResource.prototype.$url = function (path) {
1017
+ return appendPath(this.constructor.resourceUrl(this), path);
986
1018
  };
987
1019
 
988
1020
  RailsResource.prototype.processResponse = function (promise) {
989
- promise = RailsResource.callInterceptors(promise, this);
1021
+ promise = this.constructor.callInterceptors(promise, this);
990
1022
 
991
1023
  promise = promise.then(angular.bind(this, function (response) {
992
1024
  // we may not have response data
@@ -997,23 +1029,23 @@
997
1029
  return this;
998
1030
  }));
999
1031
 
1000
- return RailsResource.callAfterInterceptors(promise);
1032
+ return this.constructor.callAfterInterceptors(promise);
1001
1033
  };
1002
1034
 
1003
1035
  angular.forEach(['post', 'put', 'patch'], function (method) {
1004
1036
  RailsResource['$' + method] = function (url, data) {
1005
1037
  var config;
1006
1038
  // clone so we can manipulate w/o modifying the actual instance
1007
- data = RailsResource.transformData(angular.copy(data));
1008
- config = angular.extend({method: method, url: url, data: data}, RailsResource.getHttpConfig());
1009
- return RailsResource.processResponse($http(config));
1039
+ data = this.transformData(angular.copy(data, {}));
1040
+ config = angular.extend({method: method, url: url, data: data}, this.getHttpConfig());
1041
+ return this.processResponse($http(config));
1010
1042
  };
1011
1043
 
1012
1044
  RailsResource.prototype['$' + method] = function (url) {
1013
1045
  var data, config;
1014
1046
  // clone so we can manipulate w/o modifying the actual instance
1015
- data = RailsResource.transformData(angular.copy(this, {}));
1016
- config = angular.extend({method: method, url: url, data: data}, RailsResource.getHttpConfig());
1047
+ data = this.constructor.transformData(angular.copy(this, {}));
1048
+ config = angular.extend({method: method, url: url, data: data}, this.constructor.getHttpConfig());
1017
1049
  return this.processResponse($http(config));
1018
1050
 
1019
1051
  };
@@ -1024,12 +1056,12 @@
1024
1056
  };
1025
1057
 
1026
1058
  RailsResource.prototype.update = function () {
1027
- return this['$' + RailsResource.updateMethod](this.$url(), this);
1059
+ return this['$' + this.constructor.config.updateMethod](this.$url(), this);
1028
1060
  };
1029
1061
 
1030
1062
  RailsResource.prototype.isNew = function () {
1031
1063
  return this.id == null;
1032
- }
1064
+ };
1033
1065
 
1034
1066
  RailsResource.prototype.save = function () {
1035
1067
  if (this.isNew()) {
@@ -1037,14 +1069,14 @@
1037
1069
  } else {
1038
1070
  return this.update();
1039
1071
  }
1040
- }
1072
+ };
1041
1073
 
1042
1074
  RailsResource['$delete'] = function (url) {
1043
- return RailsResource.processResponse($http['delete'](url, RailsResource.getHttpConfig()));
1075
+ return this.processResponse($http['delete'](url, this.getHttpConfig()));
1044
1076
  };
1045
1077
 
1046
1078
  RailsResource.prototype['$delete'] = function (url) {
1047
- return this.processResponse($http['delete'](url, RailsResource.getHttpConfig()));
1079
+ return this.processResponse($http['delete'](url, this.constructor.getHttpConfig()));
1048
1080
  };
1049
1081
 
1050
1082
  //using ['delete'] instead of .delete for IE7/8 compatibility
@@ -1053,9 +1085,20 @@
1053
1085
  };
1054
1086
 
1055
1087
  return RailsResource;
1088
+ }];
1089
+ });
1090
+
1091
+ angular.module('rails').factory('railsResourceFactory', ['RailsResource', function (RailsResource) {
1092
+ return function (config) {
1093
+ function Resource() {
1094
+ Resource.__super__.constructor.apply(this, arguments);
1056
1095
  }
1057
1096
 
1058
- return railsResourceFactory;
1059
- }];
1060
- });
1097
+ RailsResource.extend(Resource);
1098
+ Resource.configure(config);
1099
+
1100
+ return Resource;
1101
+ }
1102
+ }]);
1103
+
1061
1104
  }());