programmerr47 / ganalytics Goto Github PK
View Code? Open in Web Editor NEWAnalytics library preferably sharpened for Google Analytics
License: MIT License
Analytics library preferably sharpened for Google Analytics
License: MIT License
Suggested behavior:
The description is self-explanatory. If a method doesn't have this annotation, then its name is action
The exception thrown:
java.lang.IllegalAccessException: void com.mypackage.AnalInterface$UglyConverter.() is not accessible from java.lang.Class<com.github.programmerr47.ganalytics.core.AnalyticsSingleWrapper>
We need to add supporting of val
properties in group analytics interface. Thus, the group interface will look like:
interface AnalyticsGroup {
val single: AnalyticsSingle
}
instead of
interface AnalyticsGroup {
fun single(): AnalyticsSingle
}
And usage will be like analyticsGroup.single
instead of analyticsGroup.single()
Thus, we will eliminate unnecessary brackets
Currently, we have AnalyticsGroupWrapper
as interface of all analytics interfaces, but it contains no annotation. I think it will be usefull if we could use next list of annotation on methods (equals to use these annotations on concrete analytics interface):
@Category
@HasPrefix
/ @NoPrefix
@Convention
Also, it would be great to apply several annotations on main group interface:
@HasPrefix
/ @NoPrefix
@Convention
We need to add annotation that will allow to combine interface name and method name to one action name. For example:
interface Sample {
@DesiredAnnotation fun action()
}
will give category = sample and action = sampleaction
Also, need to think about splitters. For example, to generate action = sample-action or action = sample_action
Suggested names for annotation are: @short, @Prefix, @WithPrefix, @HasPrefix
Suggested parameters:
name - specify prefix name (default is name of class in lower case)
splitter - specify splitter string (default is nothing)
Suggested behavior:
We need to think, do we really need default labels or not. And if answer is yes, we need to think, how we will implement it.
There is several ways to implement:
@DefLabel
or @LabelDef
that will be used only for methods. It will has a parameter name with specified label string.@Action
annotation and defLabels
parameter.Maybe there are other considerable ways, but currently only two are accepted.
Why?:
There are cases, when analytic with same category and action has 2 or 3 different labels.
For example: _category_= quiz, _action_= send, _label_= question/answer
In current implementation we can create an enum
with two variants:
enum class QuizSendLabel {
QUIESTION, ANSWER
}
And then pass it as a parameter of appropriate method:
interface AnalyticsQuiz {
fun send(label: QuizSendLabel)
}
But maybe in such cases it is more interesting to write something like:
interface AnalyticsQuiz {
@Action("send") @DefLabel("question") fun question()
@Action("send") @DefLabel("answer") fun answer()
}
It seems that result takes up more space, but we eliminate one enum class
with two additional instances. So it can be more important for space critical apps.
Also, with second proposed approach in the beginning of issue it will look like:
interface AnalyticsQuiz {
@Action(name = "send", defLabel = "question") fun question()
@Action(name = "send", defLabel = "answer") fun answer()
}
Which gives us possibility to not use redundant annotation, but takes up even more space.
P.S.: There is 3rd less obvious solutions: annotation @LabelFun
with parameter action
which will turn name of the method to label name and action is needed to be defined as a parameter, by user of library:
interface AnalyticsQuiz {
@LabelFun("send") fun question()
@LabelFun("send") fun answer()
}
So it will take small space, but we will eliminate redundant objects and enum.
Also, it will have additional second parameter label
for explicit defining a label.
As we using proxy as implementation of interface, it intercepts main object methods: toString
, hashCode
and equals
also, which is not right.
More over we can not use implementations comparison, if we need that. So we need to fix that thing.
We need to think and implement strategies technic for using it in a bunch with @Label annotation
Currently, when AnanlyticsGroupWrapper
is used, for each method invocation new instance of AnalyticsSingleWrapper
is created.
Next aim is to cache single wrappers to be able to reuse previous created instances for new methods with same setups and for old methods that will be invoked periodically.
Need to add @Label annotation. Currently, it will be parameterless (but then we will add strategies and e.t.c.) I think we need to implement next rules or similar to them (in order to write less code):
These rules are for parameters without @Label annotation:
Rules for @Label annotation:
@Label
, then we need to convert somehow other to valueMay be it will be good to enhance default label converter for some types.
In this case for enums by default the name will be taken and converted by chosen namingConvention
As it appeared, there are cases, when many methods in interface use the same LabelConverter
. In that case, a lot of duplicates appeared:
@HasPrefix
interface AnalyticsCar {
fun sell(@Label(AdvertConverter::class) car: Car)
fun buy(@Label(AdvertConverter::class) car: Car)
fun review(@Label(AdvertConverter::class) car: Car)
fun check(@Label(AdvertConverter::class) car: Car)
fun utilize(@Label(AdvertConverter::class) car: Car)
object CarConverter : TypedLabelConverter<Car> {
override fun convertTyped(label: Car) =
if (car.isBeauty()) "cool car"
else if (car.isUgly()) "not so cool car"
else "normal car"
}
}
It seems that in that way we can add a global converter to GanalyticsSettings
. But in other interfaces, we can have other converters for Car
. That's why we need to think about the scope of the @Label
annotation or introduce a @LabelConverter
annotation.
In second case (which is preferable) we need to think how to pass several converters: each for each type of parameters.
As the result of aforementioned example we will have:
@HasPrefix
@LabelConverter(AdvertConverter::class)
interface AnalyticsCar {
fun sell(car: Car)
fun buy(car: Car)
fun review(car: Car)
fun check(car: Car)
fun utilize(car: Car)
object CarConverter : TypedLabelConverter<Car> {
override fun convertTyped(label: Car) =
if (car.isBeauty()) "cool car"
else if (car.isUgly()) "not so cool car"
else "normal car"
}
}
Suggested behavior:
The description is self-explanatory. If we have no this annotation, the name of interface is category. Annotation without parameter is redundant and thus useless.
In case when we have an action method in Category Interface with enumeration of labels, we need to create special enum for it, if there are no other options. I think, it will be better to provide special LabelInterface. So for example, this:
interface AnalyticsPerson {
fun live(type: LiveTypeLabel)
}
enum class LiveTypeLabel { FLAT, HOUSE, APARTMENT }
will be converted to this:
interface AnalyticsPerson {
fun live(): LiveLabel
}
interface LiveLabel {
fun flat()
fun house()
fun apartment()
}
So the invocation of it will look like:
analyticsPerson.live().flat()
instead of analyticsPerson.live(FLAT)
Moreover it can help to decrease number of duplication since there could be several action methods with same enum params, and when they will be used we can totally replace one invocation with another.
Currently, the annotation will be used only for a class scope. And it will have a single parameter - an exact naming convention.
We will add few default conventions and we need to think to give a user possibility to introduce his own conventions.
In future, we need to add global settings for that.
We need to add global settings to setting up Ganalytics and possibly reduce number of annotations by customizing a default way of handle them
We need to think, if we have @HasPrefix
/@NoPrefix
annotations, does it necessary or at least fair to include @HasPostfix
/@NoPostfix
annotations?
When #1 will be done, it will be needed to add a contrary annotation in case, if we will use @Prefix
on an interface, but some methods must be used without prefixes.
P.S.: Of course, in that case, we can just split interface on two. First will use prefixes in all methods, and second will not. But the main idea behind several interfaces is to group actions by categories, where each interface represents its own category.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.